blob: 366dac15e67566243231113da9271b4fd4fc701a [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>
Antoine Pitrouc53204b2013-08-05 23:17:30 +020023#include "structmember.h"
Guido van Rossum09fdf072000-03-31 01:17:07 +000024
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000025#ifndef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000026#define UNIX
Victor Stinnera6cd0cf2011-05-02 01:05:37 +020027# ifdef __APPLE__
28# include <fcntl.h>
29# endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000030#endif
31
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000032#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000033#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000034static int
35my_getpagesize(void)
36{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000037 SYSTEM_INFO si;
38 GetSystemInfo(&si);
39 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000040}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000041
42static int
43my_getallocationgranularity (void)
44{
45
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000046 SYSTEM_INFO si;
47 GetSystemInfo(&si);
48 return si.dwAllocationGranularity;
Guido van Rossum8ce8a782007-11-01 19:42:39 +000049}
50
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000051#endif
52
53#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000054#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000055#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000056
Fred Drake145f96e2000-10-01 17:50:46 +000057#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
58static int
59my_getpagesize(void)
60{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000061 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000062}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000063
64#define my_getallocationgranularity my_getpagesize
Fred Drake145f96e2000-10-01 17:50:46 +000065#else
66#define my_getpagesize getpagesize
67#endif
68
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000069#endif /* UNIX */
70
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000071#include <string.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000072
73#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000074#include <sys/types.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000075#endif /* HAVE_SYS_TYPES_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000076
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000077/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000078#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
79# define MAP_ANONYMOUS MAP_ANON
80#endif
81
Tim Peters5ebfd362001-11-13 23:11:19 +000082typedef enum
83{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000084 ACCESS_DEFAULT,
85 ACCESS_READ,
86 ACCESS_WRITE,
87 ACCESS_COPY
Tim Peters5ebfd362001-11-13 23:11:19 +000088} access_mode;
89
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000090typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000091 PyObject_HEAD
92 char * data;
93 size_t size;
94 size_t pos; /* relative to offset */
Antoine Pitrou97696cb2011-02-21 23:46:27 +000095#ifdef MS_WINDOWS
96 PY_LONG_LONG offset;
97#else
98 off_t offset;
99#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000100 int exports;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000101
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000102#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000103 HANDLE map_handle;
104 HANDLE file_handle;
105 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000106#endif
107
108#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000109 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000110#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000111
Antoine Pitrouc53204b2013-08-05 23:17:30 +0200112 PyObject *weakreflist;
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 Pitrouc53204b2013-08-05 23:17:30 +0200139 if (m_obj->weakreflist != NULL)
140 PyObject_ClearWeakRefs((PyObject *) m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000141 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000142}
143
144static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000145mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000146{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000147 if (self->exports > 0) {
148 PyErr_SetString(PyExc_BufferError, "cannot close "\
149 "exported pointers exist");
150 return NULL;
151 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000152#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000153 /* For each resource we maintain, we need to check
154 the value is valid, and if so, free the resource
155 and set the member value to an invalid value so
156 the dealloc does not attempt to resource clearing
157 again.
158 TODO - should we check for errors in the close operations???
159 */
160 if (self->data != NULL) {
161 UnmapViewOfFile(self->data);
162 self->data = NULL;
163 }
164 if (self->map_handle != NULL) {
165 CloseHandle(self->map_handle);
166 self->map_handle = NULL;
167 }
168 if (self->file_handle != INVALID_HANDLE_VALUE) {
169 CloseHandle(self->file_handle);
170 self->file_handle = INVALID_HANDLE_VALUE;
171 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000172#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000173
174#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000175 if (0 <= self->fd)
176 (void) close(self->fd);
177 self->fd = -1;
178 if (self->data != NULL) {
179 munmap(self->data, self->size);
180 self->data = NULL;
181 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000182#endif
183
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000184 Py_INCREF(Py_None);
185 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000186}
187
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000188#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000189#define CHECK_VALID(err) \
190do { \
191 if (self->map_handle == NULL) { \
192 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
193 return err; \
194 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000195} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000196#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000197
198#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000199#define CHECK_VALID(err) \
200do { \
201 if (self->data == NULL) { \
202 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
203 return err; \
204 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000205} while (0)
206#endif /* UNIX */
207
208static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000209mmap_read_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000210 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000211{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000212 CHECK_VALID(NULL);
213 if (self->pos < self->size) {
214 char value = self->data[self->pos];
215 self->pos += 1;
Hirokazu Yamamoto3cdd5cb2010-11-04 12:09:08 +0000216 return Py_BuildValue("B", (unsigned char)value);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000217 } else {
218 PyErr_SetString(PyExc_ValueError, "read byte out of range");
219 return NULL;
220 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000221}
222
223static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000224mmap_read_line_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000225 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000226{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000227 char *start = self->data+self->pos;
228 char *eof = self->data+self->size;
229 char *eol;
230 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000231
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000232 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000233
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000234 eol = memchr(start, '\n', self->size - self->pos);
235 if (!eol)
236 eol = eof;
237 else
238 ++eol; /* we're interested in the position after the
239 newline. */
240 result = PyBytes_FromStringAndSize(start, (eol - start));
241 self->pos += (eol - start);
242 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000243}
244
Charles-François Natali4dd453c2011-06-08 19:18:14 +0200245/* Basically the "n" format code with the ability to turn None into -1. */
246static int
247mmap_convert_ssize_t(PyObject *obj, void *result) {
248 Py_ssize_t limit;
249 if (obj == Py_None) {
250 limit = -1;
251 }
252 else if (PyNumber_Check(obj)) {
253 limit = PyNumber_AsSsize_t(obj, PyExc_OverflowError);
254 if (limit == -1 && PyErr_Occurred())
255 return 0;
256 }
257 else {
258 PyErr_Format(PyExc_TypeError,
259 "integer argument expected, got '%.200s'",
260 Py_TYPE(obj)->tp_name);
261 return 0;
262 }
263 *((Py_ssize_t *)result) = limit;
264 return 1;
265}
266
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000267static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000268mmap_read_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000269 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000270{
Charles-François Natali4dd453c2011-06-08 19:18:14 +0200271 Py_ssize_t num_bytes = -1, n;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000272 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000273
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000274 CHECK_VALID(NULL);
Charles-François Natali4dd453c2011-06-08 19:18:14 +0200275 if (!PyArg_ParseTuple(args, "|O&:read", mmap_convert_ssize_t, &num_bytes))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000276 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000277
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000278 /* silently 'adjust' out-of-range requests */
279 assert(self->size >= self->pos);
280 n = self->size - self->pos;
281 /* The difference can overflow, only if self->size is greater than
282 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
283 * because the mapped area and the returned string each need more
284 * than half of the addressable memory. So we clip the size, and let
285 * the code below raise MemoryError.
286 */
287 if (n < 0)
288 n = PY_SSIZE_T_MAX;
289 if (num_bytes < 0 || num_bytes > n) {
290 num_bytes = n;
291 }
292 result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes);
293 self->pos += num_bytes;
294 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000295}
296
297static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000298mmap_gfind(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000299 PyObject *args,
300 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000301{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000302 Py_ssize_t start = self->pos;
303 Py_ssize_t end = self->size;
304 const char *needle;
305 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000306
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000307 CHECK_VALID(NULL);
308 if (!PyArg_ParseTuple(args, reverse ? "y#|nn:rfind" : "y#|nn:find",
309 &needle, &len, &start, &end)) {
310 return NULL;
311 } else {
312 const char *p, *start_p, *end_p;
313 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000314
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000315 if (start < 0)
316 start += self->size;
317 if (start < 0)
318 start = 0;
319 else if ((size_t)start > self->size)
320 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000321
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000322 if (end < 0)
323 end += self->size;
324 if (end < 0)
325 end = 0;
326 else if ((size_t)end > self->size)
327 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000328
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000329 start_p = self->data + start;
330 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000331
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000332 for (p = (reverse ? end_p - len : start_p);
333 (p >= start_p) && (p + len <= end_p); p += sign) {
334 Py_ssize_t i;
335 for (i = 0; i < len && needle[i] == p[i]; ++i)
336 /* nothing */;
337 if (i == len) {
338 return PyLong_FromSsize_t(p - self->data);
339 }
340 }
341 return PyLong_FromLong(-1);
342 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000343}
344
Georg Brandlfceab5a2008-01-19 20:08:23 +0000345static PyObject *
346mmap_find_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000347 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000348{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000349 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000350}
351
352static PyObject *
353mmap_rfind_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000354 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000355{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000356 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000357}
358
Tim Petersec0a5f02006-02-16 23:47:20 +0000359static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000360is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000361{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000362 if (self->access != ACCESS_READ)
363 return 1;
364 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
365 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000366}
367
Tim Petersec0a5f02006-02-16 23:47:20 +0000368static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000369is_resizeable(mmap_object *self)
370{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000371 if (self->exports > 0) {
372 PyErr_SetString(PyExc_BufferError,
373 "mmap can't resize with extant buffers exported.");
374 return 0;
375 }
376 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
377 return 1;
378 PyErr_Format(PyExc_TypeError,
379 "mmap can't resize a readonly or copy-on-write memory map.");
380 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000381}
382
383
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000384static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000385mmap_write_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 Py_ssize_t length;
389 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000390
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000391 CHECK_VALID(NULL);
392 if (!PyArg_ParseTuple(args, "y#:write", &data, &length))
393 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000394
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000395 if (!is_writable(self))
396 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000397
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000398 if ((self->pos + length) > self->size) {
399 PyErr_SetString(PyExc_ValueError, "data out of range");
400 return NULL;
401 }
402 memcpy(self->data+self->pos, data, length);
403 self->pos = self->pos+length;
404 Py_INCREF(Py_None);
405 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000406}
407
408static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000409mmap_write_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000410 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000411{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000412 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000413
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000414 CHECK_VALID(NULL);
415 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
416 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000417
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000418 if (!is_writable(self))
419 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000420
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000421 if (self->pos < self->size) {
422 *(self->data+self->pos) = value;
423 self->pos += 1;
424 Py_INCREF(Py_None);
425 return Py_None;
426 }
427 else {
428 PyErr_SetString(PyExc_ValueError, "write byte out of range");
429 return NULL;
430 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000431}
Tim Petersec0a5f02006-02-16 23:47:20 +0000432
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000433static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000434mmap_size_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000435 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000436{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000437 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000438
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000439#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000440 if (self->file_handle != INVALID_HANDLE_VALUE) {
441 DWORD low,high;
442 PY_LONG_LONG size;
443 low = GetFileSize(self->file_handle, &high);
444 if (low == INVALID_FILE_SIZE) {
445 /* It might be that the function appears to have failed,
446 when indeed its size equals INVALID_FILE_SIZE */
447 DWORD error = GetLastError();
448 if (error != NO_ERROR)
449 return PyErr_SetFromWindowsErr(error);
450 }
451 if (!high && low < LONG_MAX)
452 return PyLong_FromLong((long)low);
453 size = (((PY_LONG_LONG)high)<<32) + low;
454 return PyLong_FromLongLong(size);
455 } else {
456 return PyLong_FromSsize_t(self->size);
457 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000458#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000459
460#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000461 {
462 struct stat buf;
463 if (-1 == fstat(self->fd, &buf)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200464 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000465 return NULL;
466 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000467#ifdef HAVE_LARGEFILE_SUPPORT
468 return PyLong_FromLongLong(buf.st_size);
469#else
470 return PyLong_FromLong(buf.st_size);
471#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000472 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000473#endif /* UNIX */
474}
475
476/* This assumes that you want the entire file mapped,
477 / and when recreating the map will make the new file
478 / have the new size
479 /
480 / Is this really necessary? This could easily be done
481 / from python by just closing and re-opening with the
482 / new size?
483 */
484
485static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000486mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000487 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000488{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000489 Py_ssize_t new_size;
490 CHECK_VALID(NULL);
491 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
492 !is_resizeable(self)) {
493 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000494#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000495 } else {
496 DWORD dwErrCode = 0;
497 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
498 /* First, unmap the file view */
499 UnmapViewOfFile(self->data);
500 self->data = NULL;
501 /* Close the mapping object */
502 CloseHandle(self->map_handle);
503 self->map_handle = NULL;
504 /* Move to the desired EOF position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000505 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
506 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
507 off_hi = (DWORD)(self->offset >> 32);
508 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000509 SetFilePointer(self->file_handle,
510 newSizeLow, &newSizeHigh, FILE_BEGIN);
511 /* Change the size of the file */
512 SetEndOfFile(self->file_handle);
513 /* Create another mapping object and remap the file view */
514 self->map_handle = CreateFileMapping(
515 self->file_handle,
516 NULL,
517 PAGE_READWRITE,
518 0,
519 0,
520 self->tagname);
521 if (self->map_handle != NULL) {
522 self->data = (char *) MapViewOfFile(self->map_handle,
523 FILE_MAP_WRITE,
524 off_hi,
525 off_lo,
526 new_size);
527 if (self->data != NULL) {
528 self->size = new_size;
529 Py_INCREF(Py_None);
530 return Py_None;
531 } else {
532 dwErrCode = GetLastError();
533 CloseHandle(self->map_handle);
534 self->map_handle = NULL;
535 }
536 } else {
537 dwErrCode = GetLastError();
538 }
539 PyErr_SetFromWindowsErr(dwErrCode);
540 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000541#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000542
543#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000544#ifndef HAVE_MREMAP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000545 } else {
546 PyErr_SetString(PyExc_SystemError,
547 "mmap: resizing not available--no mremap()");
548 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000549#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000550 } else {
551 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000552
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000553 if (ftruncate(self->fd, self->offset + new_size) == -1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200554 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000555 return NULL;
556 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000557
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000558#ifdef MREMAP_MAYMOVE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000559 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000560#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000561 #if defined(__NetBSD__)
562 newmap = mremap(self->data, self->size, self->data, new_size, 0);
563 #else
564 newmap = mremap(self->data, self->size, new_size, 0);
565 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000566#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000567 if (newmap == (void *)-1)
568 {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200569 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000570 return NULL;
571 }
572 self->data = newmap;
573 self->size = new_size;
574 Py_INCREF(Py_None);
575 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000576#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000577#endif /* UNIX */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000578 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000579}
580
581static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000582mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000583{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000584 CHECK_VALID(NULL);
585 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000586}
587
588static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000589mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000590{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000591 Py_ssize_t offset = 0;
592 Py_ssize_t size = self->size;
593 CHECK_VALID(NULL);
594 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
595 return NULL;
596 if ((size_t)(offset + size) > self->size) {
597 PyErr_SetString(PyExc_ValueError, "flush values out of range");
598 return NULL;
599 }
R. David Murraye194dd62010-10-18 01:14:06 +0000600
601 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
602 return PyLong_FromLong(0);
603
Christian Heimesaf98da12008-01-27 15:18:18 +0000604#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000605 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000606#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000607 /* XXX semantics of return value? */
608 /* XXX flags for msync? */
609 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200610 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000611 return NULL;
612 }
613 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000614#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000615 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
616 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000617#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000618}
619
620static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000621mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000622{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000623 Py_ssize_t dist;
624 int how=0;
625 CHECK_VALID(NULL);
626 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
627 return NULL;
628 else {
629 size_t where;
630 switch (how) {
631 case 0: /* relative to start */
632 if (dist < 0)
633 goto onoutofrange;
634 where = dist;
635 break;
636 case 1: /* relative to current position */
637 if ((Py_ssize_t)self->pos + dist < 0)
638 goto onoutofrange;
639 where = self->pos + dist;
640 break;
641 case 2: /* relative to end */
642 if ((Py_ssize_t)self->size + dist < 0)
643 goto onoutofrange;
644 where = self->size + dist;
645 break;
646 default:
647 PyErr_SetString(PyExc_ValueError, "unknown seek type");
648 return NULL;
649 }
650 if (where > self->size)
651 goto onoutofrange;
652 self->pos = where;
653 Py_INCREF(Py_None);
654 return Py_None;
655 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000656
Tim Peters5ebfd362001-11-13 23:11:19 +0000657 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000658 PyErr_SetString(PyExc_ValueError, "seek out of range");
659 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000660}
661
662static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000663mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000664{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000665 unsigned long dest, src, cnt;
666 CHECK_VALID(NULL);
667 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
668 !is_writable(self)) {
669 return NULL;
670 } else {
671 /* bounds check the values */
Brett Cannon5fac8af2011-06-06 20:22:56 -0700672 if ((cnt + dest) < cnt || (cnt + src) < cnt ||
673 src > self->size || (src + cnt) > self->size ||
674 dest > self->size || (dest + cnt) > self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000675 PyErr_SetString(PyExc_ValueError,
676 "source, destination, or count out of range");
677 return NULL;
678 }
679 memmove(self->data+dest, self->data+src, cnt);
680 Py_INCREF(Py_None);
681 return Py_None;
682 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000683}
684
Georg Brandl0bccc182010-08-01 14:50:00 +0000685static PyObject *
686mmap_closed_get(mmap_object *self)
687{
688#ifdef MS_WINDOWS
689 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
690#elif defined(UNIX)
691 return PyBool_FromLong(self->data == NULL ? 1 : 0);
692#endif
693}
694
695static PyObject *
696mmap__enter__method(mmap_object *self, PyObject *args)
697{
698 CHECK_VALID(NULL);
699
700 Py_INCREF(self);
701 return (PyObject *)self;
702}
703
704static PyObject *
705mmap__exit__method(PyObject *self, PyObject *args)
706{
Martin v. Löwisbd928fe2011-10-14 10:20:37 +0200707 _Py_IDENTIFIER(close);
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200708
709 return _PyObject_CallMethodId(self, &PyId_close, NULL);
Georg Brandl0bccc182010-08-01 14:50:00 +0000710}
711
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000712static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000713 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
714 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
715 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
716 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
717 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
718 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
719 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
720 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
721 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
722 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
723 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
724 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
725 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
726 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000727 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
728 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000729 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000730};
731
Georg Brandl0bccc182010-08-01 14:50:00 +0000732static PyGetSetDef mmap_object_getset[] = {
733 {"closed", (getter) mmap_closed_get, NULL, NULL},
734 {NULL}
735};
736
737
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000738/* Functions for treating an mmap'ed file as a buffer */
739
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000740static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000741mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000742{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000743 CHECK_VALID(-1);
744 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
745 (self->access == ACCESS_READ), flags) < 0)
746 return -1;
747 self->exports++;
748 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000749}
750
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000751static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000752mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000753{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000754 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000755}
756
Martin v. Löwis18e16552006-02-15 17:27:45 +0000757static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000758mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000759{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000760 CHECK_VALID(-1);
761 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000762}
763
764static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000765mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000766{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000767 CHECK_VALID(NULL);
768 if (i < 0 || (size_t)i >= self->size) {
769 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
770 return NULL;
771 }
772 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000773}
774
775static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000776mmap_subscript(mmap_object *self, PyObject *item)
777{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000778 CHECK_VALID(NULL);
779 if (PyIndex_Check(item)) {
780 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
781 if (i == -1 && PyErr_Occurred())
782 return NULL;
783 if (i < 0)
784 i += self->size;
785 if (i < 0 || (size_t)i >= self->size) {
786 PyErr_SetString(PyExc_IndexError,
787 "mmap index out of range");
788 return NULL;
789 }
790 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
791 }
792 else if (PySlice_Check(item)) {
793 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000794
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000795 if (PySlice_GetIndicesEx(item, self->size,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000796 &start, &stop, &step, &slicelen) < 0) {
797 return NULL;
798 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000799
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000800 if (slicelen <= 0)
801 return PyBytes_FromStringAndSize("", 0);
802 else if (step == 1)
803 return PyBytes_FromStringAndSize(self->data + start,
804 slicelen);
805 else {
806 char *result_buf = (char *)PyMem_Malloc(slicelen);
807 Py_ssize_t cur, i;
808 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000809
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000810 if (result_buf == NULL)
811 return PyErr_NoMemory();
812 for (cur = start, i = 0; i < slicelen;
813 cur += step, i++) {
814 result_buf[i] = self->data[cur];
815 }
816 result = PyBytes_FromStringAndSize(result_buf,
817 slicelen);
818 PyMem_Free(result_buf);
819 return result;
820 }
821 }
822 else {
823 PyErr_SetString(PyExc_TypeError,
824 "mmap indices must be integers");
825 return NULL;
826 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000827}
828
829static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000830mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000831{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000832 CHECK_VALID(NULL);
833 PyErr_SetString(PyExc_SystemError,
834 "mmaps don't support concatenation");
835 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000836}
837
838static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000839mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000840{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000841 CHECK_VALID(NULL);
842 PyErr_SetString(PyExc_SystemError,
843 "mmaps don't support repeat operation");
844 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000845}
846
847static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000848mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000849{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000850 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000851
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000852 CHECK_VALID(-1);
853 if (i < 0 || (size_t)i >= self->size) {
854 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
855 return -1;
856 }
857 if (v == NULL) {
858 PyErr_SetString(PyExc_TypeError,
859 "mmap object doesn't support item deletion");
860 return -1;
861 }
862 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
863 PyErr_SetString(PyExc_IndexError,
864 "mmap assignment must be length-1 bytes()");
865 return -1;
866 }
867 if (!is_writable(self))
868 return -1;
869 buf = PyBytes_AsString(v);
870 self->data[i] = buf[0];
871 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000872}
873
Thomas Woutersed03b412007-08-28 21:37:11 +0000874static int
875mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
876{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000877 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000878
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000879 if (!is_writable(self))
880 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000881
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000882 if (PyIndex_Check(item)) {
883 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
884 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000885
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000886 if (i == -1 && PyErr_Occurred())
887 return -1;
888 if (i < 0)
889 i += self->size;
890 if (i < 0 || (size_t)i >= self->size) {
891 PyErr_SetString(PyExc_IndexError,
892 "mmap index out of range");
893 return -1;
894 }
895 if (value == NULL) {
896 PyErr_SetString(PyExc_TypeError,
897 "mmap doesn't support item deletion");
898 return -1;
899 }
900 if (!PyIndex_Check(value)) {
901 PyErr_SetString(PyExc_TypeError,
902 "mmap item value must be an int");
903 return -1;
904 }
905 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
906 if (v == -1 && PyErr_Occurred())
907 return -1;
908 if (v < 0 || v > 255) {
909 PyErr_SetString(PyExc_ValueError,
910 "mmap item value must be "
911 "in range(0, 256)");
912 return -1;
913 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000914 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000915 return 0;
916 }
917 else if (PySlice_Check(item)) {
918 Py_ssize_t start, stop, step, slicelen;
919 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000920
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000921 if (PySlice_GetIndicesEx(item,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000922 self->size, &start, &stop,
923 &step, &slicelen) < 0) {
924 return -1;
925 }
926 if (value == NULL) {
927 PyErr_SetString(PyExc_TypeError,
928 "mmap object doesn't support slice deletion");
929 return -1;
930 }
931 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
932 return -1;
933 if (vbuf.len != slicelen) {
934 PyErr_SetString(PyExc_IndexError,
935 "mmap slice assignment is wrong size");
936 PyBuffer_Release(&vbuf);
937 return -1;
938 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000939
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000940 if (slicelen == 0) {
941 }
942 else if (step == 1) {
943 memcpy(self->data + start, vbuf.buf, slicelen);
944 }
945 else {
946 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000947
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000948 for (cur = start, i = 0;
949 i < slicelen;
950 cur += step, i++)
951 {
952 self->data[cur] = ((char *)vbuf.buf)[i];
953 }
954 }
955 PyBuffer_Release(&vbuf);
956 return 0;
957 }
958 else {
959 PyErr_SetString(PyExc_TypeError,
960 "mmap indices must be integer");
961 return -1;
962 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000963}
964
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000965static PySequenceMethods mmap_as_sequence = {
Stefan Krah23186992012-03-06 15:37:36 +0100966 (lenfunc)mmap_length, /*sq_length*/
967 (binaryfunc)mmap_concat, /*sq_concat*/
968 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
969 (ssizeargfunc)mmap_item, /*sq_item*/
970 0, /*sq_slice*/
971 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
972 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000973};
974
Thomas Woutersed03b412007-08-28 21:37:11 +0000975static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000976 (lenfunc)mmap_length,
977 (binaryfunc)mmap_subscript,
978 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000979};
980
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000981static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000982 (getbufferproc)mmap_buffer_getbuf,
983 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000984};
985
Georg Brandl86def6c2008-01-21 20:36:10 +0000986static PyObject *
987new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
988
Christian Heimese1c98112008-01-21 11:20:28 +0000989PyDoc_STRVAR(mmap_doc,
990"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
991\n\
992Maps length bytes from the file specified by the file handle fileno,\n\
993and returns a mmap object. If length is larger than the current size\n\
994of the file, the file is extended to contain length bytes. If length\n\
995is 0, the maximum length of the map is the current size of the file,\n\
996except that if the file is empty Windows raises an exception (you cannot\n\
997create an empty mapping on Windows).\n\
998\n\
999Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1000\n\
1001Maps length bytes from the file specified by the file descriptor fileno,\n\
1002and returns a mmap object. If length is 0, the maximum length of the map\n\
1003will be the current size of the file when mmap is called.\n\
1004flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1005private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +00001006object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +00001007that's shared with all other processes mapping the same areas of the file.\n\
1008The default value is MAP_SHARED.\n\
1009\n\
1010To map anonymous memory, pass -1 as the fileno (both versions).");
1011
1012
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001013static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001014 PyVarObject_HEAD_INIT(NULL, 0)
1015 "mmap.mmap", /* tp_name */
1016 sizeof(mmap_object), /* tp_size */
1017 0, /* tp_itemsize */
1018 /* methods */
1019 (destructor) mmap_object_dealloc, /* tp_dealloc */
1020 0, /* tp_print */
1021 0, /* tp_getattr */
1022 0, /* tp_setattr */
1023 0, /* tp_reserved */
1024 0, /* tp_repr */
1025 0, /* tp_as_number */
1026 &mmap_as_sequence, /*tp_as_sequence*/
1027 &mmap_as_mapping, /*tp_as_mapping*/
1028 0, /*tp_hash*/
1029 0, /*tp_call*/
1030 0, /*tp_str*/
1031 PyObject_GenericGetAttr, /*tp_getattro*/
1032 0, /*tp_setattro*/
1033 &mmap_as_buffer, /*tp_as_buffer*/
Stefan Krah23186992012-03-06 15:37:36 +01001034 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001035 mmap_doc, /*tp_doc*/
1036 0, /* tp_traverse */
1037 0, /* tp_clear */
1038 0, /* tp_richcompare */
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001039 offsetof(mmap_object, weakreflist), /* tp_weaklistoffset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001040 0, /* tp_iter */
1041 0, /* tp_iternext */
1042 mmap_object_methods, /* tp_methods */
1043 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001044 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001045 0, /* tp_base */
1046 0, /* tp_dict */
1047 0, /* tp_descr_get */
1048 0, /* tp_descr_set */
1049 0, /* tp_dictoffset */
Stefan Krah23186992012-03-06 15:37:36 +01001050 0, /* tp_init */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001051 PyType_GenericAlloc, /* tp_alloc */
1052 new_mmap_object, /* tp_new */
Stefan Krah23186992012-03-06 15:37:36 +01001053 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001054};
1055
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001056
1057/* extract the map size from the given PyObject
1058
Thomas Wouters7e474022000-07-16 12:04:32 +00001059 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001060 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001061static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001062_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001063{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001064 if (o == NULL)
1065 return 0;
1066 if (PyIndex_Check(o)) {
1067 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1068 if (i==-1 && PyErr_Occurred())
1069 return -1;
1070 if (i < 0) {
1071 PyErr_Format(PyExc_OverflowError,
1072 "memory mapped %s must be positive",
1073 param);
1074 return -1;
1075 }
1076 return i;
1077 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001078
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001079 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1080 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001081}
1082
Tim Petersec0a5f02006-02-16 23:47:20 +00001083#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001084#ifdef HAVE_LARGEFILE_SUPPORT
1085#define _Py_PARSE_OFF_T "L"
1086#else
1087#define _Py_PARSE_OFF_T "l"
1088#endif
1089
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001090static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001091new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001092{
Neal Norwitzb5673922002-09-05 21:48:07 +00001093#ifdef HAVE_FSTAT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001094 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001095#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001096 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001097 PyObject *map_size_obj = NULL;
1098 Py_ssize_t map_size;
1099 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001100 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1101 int devzero = -1;
1102 int access = (int)ACCESS_DEFAULT;
1103 static char *keywords[] = {"fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001104 "flags", "prot",
1105 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001106
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001107 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001108 &fd, &map_size_obj, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001109 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001110 return NULL;
1111 map_size = _GetMapSize(map_size_obj, "size");
1112 if (map_size < 0)
1113 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001114 if (offset < 0) {
1115 PyErr_SetString(PyExc_OverflowError,
1116 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001117 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001118 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001119
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001120 if ((access != (int)ACCESS_DEFAULT) &&
1121 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1122 return PyErr_Format(PyExc_ValueError,
1123 "mmap can't specify both access and flags, prot.");
1124 switch ((access_mode)access) {
1125 case ACCESS_READ:
1126 flags = MAP_SHARED;
1127 prot = PROT_READ;
1128 break;
1129 case ACCESS_WRITE:
1130 flags = MAP_SHARED;
1131 prot = PROT_READ | PROT_WRITE;
1132 break;
1133 case ACCESS_COPY:
1134 flags = MAP_PRIVATE;
1135 prot = PROT_READ | PROT_WRITE;
1136 break;
1137 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001138 /* map prot to access type */
1139 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1140 /* ACCESS_DEFAULT */
1141 }
1142 else if (prot & PROT_WRITE) {
1143 access = ACCESS_WRITE;
1144 }
1145 else {
1146 access = ACCESS_READ;
1147 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001148 break;
1149 default:
1150 return PyErr_Format(PyExc_ValueError,
1151 "mmap invalid access parameter.");
1152 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001153
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001154#ifdef __APPLE__
1155 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1156 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1157 if (fd != -1)
1158 (void)fcntl(fd, F_FULLFSYNC);
1159#endif
Neal Norwitzb5673922002-09-05 21:48:07 +00001160#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001161# ifdef __VMS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001162 /* on OpenVMS we must ensure that all bytes are written to the file */
1163 if (fd != -1) {
1164 fsync(fd);
1165 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001166# endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001167 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1168 if (map_size == 0) {
Jesus Cea941bfcc2012-09-10 00:27:55 +02001169 if (st.st_size == 0) {
1170 PyErr_SetString(PyExc_ValueError,
1171 "cannot mmap an empty file");
1172 return NULL;
1173 }
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001174 if (offset >= st.st_size) {
1175 PyErr_SetString(PyExc_ValueError,
1176 "mmap offset is greater than file size");
1177 return NULL;
1178 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001179 if (st.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001180 PyErr_SetString(PyExc_ValueError,
1181 "mmap length is too large");
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001182 return NULL;
1183 }
1184 map_size = (Py_ssize_t) (st.st_size - offset);
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001185 } else if (offset + (size_t)map_size > st.st_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001186 PyErr_SetString(PyExc_ValueError,
1187 "mmap length is greater than file size");
1188 return NULL;
1189 }
1190 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001191#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001192 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1193 if (m_obj == NULL) {return NULL;}
1194 m_obj->data = NULL;
1195 m_obj->size = (size_t) map_size;
1196 m_obj->pos = (size_t) 0;
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001197 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001198 m_obj->exports = 0;
1199 m_obj->offset = offset;
1200 if (fd == -1) {
1201 m_obj->fd = -1;
1202 /* Assume the caller wants to map anonymous memory.
1203 This is the same behaviour as Windows. mmap.mmap(-1, size)
1204 on both Windows and Unix map anonymous memory.
1205 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001206#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001207 /* BSD way to map anonymous memory */
1208 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001209#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001210 /* SVR4 method to map anonymous memory is to open /dev/zero */
Victor Stinnerdaf45552013-08-28 00:53:59 +02001211 fd = devzero = _Py_open("/dev/zero", O_RDWR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001212 if (devzero == -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 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001217#endif
Victor Stinnerdaf45552013-08-28 00:53:59 +02001218 }
1219 else {
1220 m_obj->fd = _Py_dup(fd);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001221 if (m_obj->fd == -1) {
1222 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001223 return NULL;
1224 }
1225 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001226
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001227 m_obj->data = mmap(NULL, map_size,
1228 prot, flags,
1229 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001230
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001231 if (devzero != -1) {
1232 close(devzero);
1233 }
1234
1235 if (m_obj->data == (char *)-1) {
1236 m_obj->data = NULL;
1237 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001238 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001239 return NULL;
1240 }
1241 m_obj->access = (access_mode)access;
1242 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001243}
1244#endif /* UNIX */
1245
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001246#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001247
1248/* A note on sizes and offsets: while the actual map size must hold in a
1249 Py_ssize_t, both the total file size and the start offset can be longer
1250 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1251*/
1252
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001253static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001254new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001255{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001256 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001257 PyObject *map_size_obj = NULL;
1258 Py_ssize_t map_size;
1259 PY_LONG_LONG offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001260 DWORD off_hi; /* upper 32 bits of offset */
1261 DWORD off_lo; /* lower 32 bits of offset */
1262 DWORD size_hi; /* upper 32 bits of size */
1263 DWORD size_lo; /* lower 32 bits of size */
1264 char *tagname = "";
1265 DWORD dwErr = 0;
1266 int fileno;
1267 HANDLE fh = 0;
1268 int access = (access_mode)ACCESS_DEFAULT;
1269 DWORD flProtect, dwDesiredAccess;
1270 static char *keywords[] = { "fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001271 "tagname",
1272 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001273
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001274 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001275 &fileno, &map_size_obj,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001276 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001277 return NULL;
1278 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001279
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001280 switch((access_mode)access) {
1281 case ACCESS_READ:
1282 flProtect = PAGE_READONLY;
1283 dwDesiredAccess = FILE_MAP_READ;
1284 break;
1285 case ACCESS_DEFAULT: case ACCESS_WRITE:
1286 flProtect = PAGE_READWRITE;
1287 dwDesiredAccess = FILE_MAP_WRITE;
1288 break;
1289 case ACCESS_COPY:
1290 flProtect = PAGE_WRITECOPY;
1291 dwDesiredAccess = FILE_MAP_COPY;
1292 break;
1293 default:
1294 return PyErr_Format(PyExc_ValueError,
1295 "mmap invalid access parameter.");
1296 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001297
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001298 map_size = _GetMapSize(map_size_obj, "size");
1299 if (map_size < 0)
1300 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001301 if (offset < 0) {
1302 PyErr_SetString(PyExc_OverflowError,
1303 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001304 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001305 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001306
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001307 /* assume -1 and 0 both mean invalid filedescriptor
1308 to 'anonymously' map memory.
1309 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1310 XXX: Should this code be added?
1311 if (fileno == 0)
1312 PyErr_WarnEx(PyExc_DeprecationWarning,
1313 "don't use 0 for anonymous memory",
1314 1);
1315 */
1316 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001317 /* Ensure that fileno is within the CRT's valid range */
1318 if (_PyVerify_fd(fileno) == 0) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001319 PyErr_SetFromErrno(PyExc_OSError);
Brian Curtinea47eaa2010-08-01 15:26:26 +00001320 return NULL;
1321 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001322 fh = (HANDLE)_get_osfhandle(fileno);
1323 if (fh==(HANDLE)-1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001324 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001325 return NULL;
1326 }
1327 /* Win9x appears to need us seeked to zero */
1328 lseek(fileno, 0, SEEK_SET);
1329 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001330
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001331 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1332 if (m_obj == NULL)
1333 return NULL;
1334 /* Set every field to an invalid marker, so we can safely
1335 destruct the object in the face of failure */
1336 m_obj->data = NULL;
1337 m_obj->file_handle = INVALID_HANDLE_VALUE;
1338 m_obj->map_handle = NULL;
1339 m_obj->tagname = NULL;
1340 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001341
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001342 if (fh) {
1343 /* It is necessary to duplicate the handle, so the
1344 Python code can close it on us */
1345 if (!DuplicateHandle(
1346 GetCurrentProcess(), /* source process handle */
1347 fh, /* handle to be duplicated */
1348 GetCurrentProcess(), /* target proc handle */
1349 (LPHANDLE)&m_obj->file_handle, /* result */
1350 0, /* access - ignored due to options value */
1351 FALSE, /* inherited by child processes? */
1352 DUPLICATE_SAME_ACCESS)) { /* options */
1353 dwErr = GetLastError();
1354 Py_DECREF(m_obj);
1355 PyErr_SetFromWindowsErr(dwErr);
1356 return NULL;
1357 }
1358 if (!map_size) {
1359 DWORD low,high;
1360 low = GetFileSize(fh, &high);
1361 /* low might just happen to have the value INVALID_FILE_SIZE;
1362 so we need to check the last error also. */
1363 if (low == INVALID_FILE_SIZE &&
1364 (dwErr = GetLastError()) != NO_ERROR) {
1365 Py_DECREF(m_obj);
1366 return PyErr_SetFromWindowsErr(dwErr);
1367 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001368
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001369 size = (((PY_LONG_LONG) high) << 32) + low;
Jesus Cea1f2799b2012-09-10 22:49:50 +02001370 if (size == 0) {
1371 PyErr_SetString(PyExc_ValueError,
1372 "cannot mmap an empty file");
Jesus Ceae8db3562012-09-10 22:58:07 +02001373 Py_DECREF(m_obj);
Jesus Cea1f2799b2012-09-10 22:49:50 +02001374 return NULL;
1375 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001376 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001377 PyErr_SetString(PyExc_ValueError,
1378 "mmap offset is greater than file size");
1379 Py_DECREF(m_obj);
1380 return NULL;
1381 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001382 if (size - offset > PY_SSIZE_T_MAX) {
1383 PyErr_SetString(PyExc_ValueError,
1384 "mmap length is too large");
1385 Py_DECREF(m_obj);
1386 return NULL;
1387 }
1388 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001389 } else {
1390 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001391 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001392 }
1393 }
1394 else {
1395 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001396 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001397 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001398
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001399 /* set the initial position */
1400 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001401
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001402 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001403 m_obj->exports = 0;
1404 /* set the tag name */
1405 if (tagname != NULL && *tagname != '\0') {
1406 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1407 if (m_obj->tagname == NULL) {
1408 PyErr_NoMemory();
1409 Py_DECREF(m_obj);
1410 return NULL;
1411 }
1412 strcpy(m_obj->tagname, tagname);
1413 }
1414 else
1415 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001416
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001417 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001418 size_hi = (DWORD)(size >> 32);
1419 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001420 off_hi = (DWORD)(offset >> 32);
1421 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001422 /* For files, it would be sufficient to pass 0 as size.
1423 For anonymous maps, we have to pass the size explicitly. */
1424 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1425 NULL,
1426 flProtect,
1427 size_hi,
1428 size_lo,
1429 m_obj->tagname);
1430 if (m_obj->map_handle != NULL) {
1431 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1432 dwDesiredAccess,
1433 off_hi,
1434 off_lo,
1435 m_obj->size);
1436 if (m_obj->data != NULL)
1437 return (PyObject *)m_obj;
1438 else {
1439 dwErr = GetLastError();
1440 CloseHandle(m_obj->map_handle);
1441 m_obj->map_handle = NULL;
1442 }
1443 } else
1444 dwErr = GetLastError();
1445 Py_DECREF(m_obj);
1446 PyErr_SetFromWindowsErr(dwErr);
1447 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001448}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001449#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001450
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001451static void
1452setint(PyObject *d, const char *name, long value)
1453{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001454 PyObject *o = PyLong_FromLong(value);
1455 if (o && PyDict_SetItemString(d, name, o) == 0) {
1456 Py_DECREF(o);
1457 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001458}
1459
Martin v. Löwis1a214512008-06-11 05:26:20 +00001460
1461static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001462 PyModuleDef_HEAD_INIT,
1463 "mmap",
1464 NULL,
1465 -1,
1466 NULL,
1467 NULL,
1468 NULL,
1469 NULL,
1470 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001471};
1472
Mark Hammond62b1ab12002-07-23 06:31:15 +00001473PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001474PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001475{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001476 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001477
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001478 if (PyType_Ready(&mmap_object_type) < 0)
1479 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001480
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001481 module = PyModule_Create(&mmapmodule);
1482 if (module == NULL)
1483 return NULL;
1484 dict = PyModule_GetDict(module);
1485 if (!dict)
1486 return NULL;
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001487 PyDict_SetItemString(dict, "error", PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001488 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001489#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001490 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001491#endif
1492#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001493 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001494#endif
1495#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001496 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001497#endif
1498
1499#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001500 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001501#endif
1502#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001503 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001504#endif
1505#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001506 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001507#endif
1508#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001509 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001510#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001511#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001512 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1513 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001514#endif
1515
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001516 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001517
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001518 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001519
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001520 setint(dict, "ACCESS_READ", ACCESS_READ);
1521 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1522 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1523 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001524}