blob: 137142420f4febb430cdced19554cabeba7cd45d [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
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300712#ifdef MS_WINDOWS
713static PyObject *
714mmap__sizeof__method(mmap_object *self, void *unused)
715{
716 Py_ssize_t res;
717
718 res = sizeof(mmap_object);
719 if (self->tagname)
720 res += strlen(self->tagname) + 1;
721 return PyLong_FromSsize_t(res);
722}
723#endif
724
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000725static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000726 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
727 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
728 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
729 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
730 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
731 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
732 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
733 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
734 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
735 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
736 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
737 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
738 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
739 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000740 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
741 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300742#ifdef MS_WINDOWS
743 {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS},
744#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000745 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000746};
747
Georg Brandl0bccc182010-08-01 14:50:00 +0000748static PyGetSetDef mmap_object_getset[] = {
749 {"closed", (getter) mmap_closed_get, NULL, NULL},
750 {NULL}
751};
752
753
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000754/* Functions for treating an mmap'ed file as a buffer */
755
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000756static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000757mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000758{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000759 CHECK_VALID(-1);
760 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
761 (self->access == ACCESS_READ), flags) < 0)
762 return -1;
763 self->exports++;
764 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000765}
766
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000767static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000768mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000769{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000770 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000771}
772
Martin v. Löwis18e16552006-02-15 17:27:45 +0000773static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000774mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000775{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000776 CHECK_VALID(-1);
777 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000778}
779
780static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000781mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000782{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000783 CHECK_VALID(NULL);
784 if (i < 0 || (size_t)i >= self->size) {
785 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
786 return NULL;
787 }
788 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000789}
790
791static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000792mmap_subscript(mmap_object *self, PyObject *item)
793{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000794 CHECK_VALID(NULL);
795 if (PyIndex_Check(item)) {
796 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
797 if (i == -1 && PyErr_Occurred())
798 return NULL;
799 if (i < 0)
800 i += self->size;
801 if (i < 0 || (size_t)i >= self->size) {
802 PyErr_SetString(PyExc_IndexError,
803 "mmap index out of range");
804 return NULL;
805 }
806 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
807 }
808 else if (PySlice_Check(item)) {
809 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000810
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000811 if (PySlice_GetIndicesEx(item, self->size,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000812 &start, &stop, &step, &slicelen) < 0) {
813 return NULL;
814 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000815
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000816 if (slicelen <= 0)
817 return PyBytes_FromStringAndSize("", 0);
818 else if (step == 1)
819 return PyBytes_FromStringAndSize(self->data + start,
820 slicelen);
821 else {
822 char *result_buf = (char *)PyMem_Malloc(slicelen);
823 Py_ssize_t cur, i;
824 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000825
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000826 if (result_buf == NULL)
827 return PyErr_NoMemory();
828 for (cur = start, i = 0; i < slicelen;
829 cur += step, i++) {
830 result_buf[i] = self->data[cur];
831 }
832 result = PyBytes_FromStringAndSize(result_buf,
833 slicelen);
834 PyMem_Free(result_buf);
835 return result;
836 }
837 }
838 else {
839 PyErr_SetString(PyExc_TypeError,
840 "mmap indices must be integers");
841 return NULL;
842 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000843}
844
845static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000846mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000847{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000848 CHECK_VALID(NULL);
849 PyErr_SetString(PyExc_SystemError,
850 "mmaps don't support concatenation");
851 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000852}
853
854static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000855mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000856{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000857 CHECK_VALID(NULL);
858 PyErr_SetString(PyExc_SystemError,
859 "mmaps don't support repeat operation");
860 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000861}
862
863static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000864mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000865{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000866 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000867
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000868 CHECK_VALID(-1);
869 if (i < 0 || (size_t)i >= self->size) {
870 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
871 return -1;
872 }
873 if (v == NULL) {
874 PyErr_SetString(PyExc_TypeError,
875 "mmap object doesn't support item deletion");
876 return -1;
877 }
878 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
879 PyErr_SetString(PyExc_IndexError,
880 "mmap assignment must be length-1 bytes()");
881 return -1;
882 }
883 if (!is_writable(self))
884 return -1;
885 buf = PyBytes_AsString(v);
886 self->data[i] = buf[0];
887 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000888}
889
Thomas Woutersed03b412007-08-28 21:37:11 +0000890static int
891mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
892{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000893 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000894
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000895 if (!is_writable(self))
896 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000897
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000898 if (PyIndex_Check(item)) {
899 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
900 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000901
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000902 if (i == -1 && PyErr_Occurred())
903 return -1;
904 if (i < 0)
905 i += self->size;
906 if (i < 0 || (size_t)i >= self->size) {
907 PyErr_SetString(PyExc_IndexError,
908 "mmap index out of range");
909 return -1;
910 }
911 if (value == NULL) {
912 PyErr_SetString(PyExc_TypeError,
913 "mmap doesn't support item deletion");
914 return -1;
915 }
916 if (!PyIndex_Check(value)) {
917 PyErr_SetString(PyExc_TypeError,
918 "mmap item value must be an int");
919 return -1;
920 }
921 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
922 if (v == -1 && PyErr_Occurred())
923 return -1;
924 if (v < 0 || v > 255) {
925 PyErr_SetString(PyExc_ValueError,
926 "mmap item value must be "
927 "in range(0, 256)");
928 return -1;
929 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000930 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000931 return 0;
932 }
933 else if (PySlice_Check(item)) {
934 Py_ssize_t start, stop, step, slicelen;
935 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000936
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000937 if (PySlice_GetIndicesEx(item,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000938 self->size, &start, &stop,
939 &step, &slicelen) < 0) {
940 return -1;
941 }
942 if (value == NULL) {
943 PyErr_SetString(PyExc_TypeError,
944 "mmap object doesn't support slice deletion");
945 return -1;
946 }
947 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
948 return -1;
949 if (vbuf.len != slicelen) {
950 PyErr_SetString(PyExc_IndexError,
951 "mmap slice assignment is wrong size");
952 PyBuffer_Release(&vbuf);
953 return -1;
954 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000955
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000956 if (slicelen == 0) {
957 }
958 else if (step == 1) {
959 memcpy(self->data + start, vbuf.buf, slicelen);
960 }
961 else {
962 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000963
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000964 for (cur = start, i = 0;
965 i < slicelen;
966 cur += step, i++)
967 {
968 self->data[cur] = ((char *)vbuf.buf)[i];
969 }
970 }
971 PyBuffer_Release(&vbuf);
972 return 0;
973 }
974 else {
975 PyErr_SetString(PyExc_TypeError,
976 "mmap indices must be integer");
977 return -1;
978 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000979}
980
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000981static PySequenceMethods mmap_as_sequence = {
Stefan Krah23186992012-03-06 15:37:36 +0100982 (lenfunc)mmap_length, /*sq_length*/
983 (binaryfunc)mmap_concat, /*sq_concat*/
984 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
985 (ssizeargfunc)mmap_item, /*sq_item*/
986 0, /*sq_slice*/
987 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
988 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000989};
990
Thomas Woutersed03b412007-08-28 21:37:11 +0000991static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000992 (lenfunc)mmap_length,
993 (binaryfunc)mmap_subscript,
994 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000995};
996
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000997static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000998 (getbufferproc)mmap_buffer_getbuf,
999 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001000};
1001
Georg Brandl86def6c2008-01-21 20:36:10 +00001002static PyObject *
1003new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1004
Christian Heimese1c98112008-01-21 11:20:28 +00001005PyDoc_STRVAR(mmap_doc,
1006"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1007\n\
1008Maps length bytes from the file specified by the file handle fileno,\n\
1009and returns a mmap object. If length is larger than the current size\n\
1010of the file, the file is extended to contain length bytes. If length\n\
1011is 0, the maximum length of the map is the current size of the file,\n\
1012except that if the file is empty Windows raises an exception (you cannot\n\
1013create an empty mapping on Windows).\n\
1014\n\
1015Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1016\n\
1017Maps length bytes from the file specified by the file descriptor fileno,\n\
1018and returns a mmap object. If length is 0, the maximum length of the map\n\
1019will be the current size of the file when mmap is called.\n\
1020flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1021private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +00001022object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +00001023that's shared with all other processes mapping the same areas of the file.\n\
1024The default value is MAP_SHARED.\n\
1025\n\
1026To map anonymous memory, pass -1 as the fileno (both versions).");
1027
1028
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001029static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001030 PyVarObject_HEAD_INIT(NULL, 0)
1031 "mmap.mmap", /* tp_name */
1032 sizeof(mmap_object), /* tp_size */
1033 0, /* tp_itemsize */
1034 /* methods */
1035 (destructor) mmap_object_dealloc, /* tp_dealloc */
1036 0, /* tp_print */
1037 0, /* tp_getattr */
1038 0, /* tp_setattr */
1039 0, /* tp_reserved */
1040 0, /* tp_repr */
1041 0, /* tp_as_number */
1042 &mmap_as_sequence, /*tp_as_sequence*/
1043 &mmap_as_mapping, /*tp_as_mapping*/
1044 0, /*tp_hash*/
1045 0, /*tp_call*/
1046 0, /*tp_str*/
1047 PyObject_GenericGetAttr, /*tp_getattro*/
1048 0, /*tp_setattro*/
1049 &mmap_as_buffer, /*tp_as_buffer*/
Stefan Krah23186992012-03-06 15:37:36 +01001050 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001051 mmap_doc, /*tp_doc*/
1052 0, /* tp_traverse */
1053 0, /* tp_clear */
1054 0, /* tp_richcompare */
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001055 offsetof(mmap_object, weakreflist), /* tp_weaklistoffset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001056 0, /* tp_iter */
1057 0, /* tp_iternext */
1058 mmap_object_methods, /* tp_methods */
1059 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001060 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001061 0, /* tp_base */
1062 0, /* tp_dict */
1063 0, /* tp_descr_get */
1064 0, /* tp_descr_set */
1065 0, /* tp_dictoffset */
Stefan Krah23186992012-03-06 15:37:36 +01001066 0, /* tp_init */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001067 PyType_GenericAlloc, /* tp_alloc */
1068 new_mmap_object, /* tp_new */
Stefan Krah23186992012-03-06 15:37:36 +01001069 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001070};
1071
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001072
1073/* extract the map size from the given PyObject
1074
Thomas Wouters7e474022000-07-16 12:04:32 +00001075 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001076 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001077static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001078_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001079{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001080 if (o == NULL)
1081 return 0;
1082 if (PyIndex_Check(o)) {
1083 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1084 if (i==-1 && PyErr_Occurred())
1085 return -1;
1086 if (i < 0) {
1087 PyErr_Format(PyExc_OverflowError,
1088 "memory mapped %s must be positive",
1089 param);
1090 return -1;
1091 }
1092 return i;
1093 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001094
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001095 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1096 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001097}
1098
Tim Petersec0a5f02006-02-16 23:47:20 +00001099#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001100#ifdef HAVE_LARGEFILE_SUPPORT
1101#define _Py_PARSE_OFF_T "L"
1102#else
1103#define _Py_PARSE_OFF_T "l"
1104#endif
1105
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001106static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001107new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001108{
Neal Norwitzb5673922002-09-05 21:48:07 +00001109#ifdef HAVE_FSTAT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001110 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001111#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001112 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001113 PyObject *map_size_obj = NULL;
1114 Py_ssize_t map_size;
1115 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001116 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1117 int devzero = -1;
1118 int access = (int)ACCESS_DEFAULT;
1119 static char *keywords[] = {"fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001120 "flags", "prot",
1121 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001122
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001123 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001124 &fd, &map_size_obj, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001125 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001126 return NULL;
1127 map_size = _GetMapSize(map_size_obj, "size");
1128 if (map_size < 0)
1129 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001130 if (offset < 0) {
1131 PyErr_SetString(PyExc_OverflowError,
1132 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001133 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001134 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001135
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001136 if ((access != (int)ACCESS_DEFAULT) &&
1137 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1138 return PyErr_Format(PyExc_ValueError,
1139 "mmap can't specify both access and flags, prot.");
1140 switch ((access_mode)access) {
1141 case ACCESS_READ:
1142 flags = MAP_SHARED;
1143 prot = PROT_READ;
1144 break;
1145 case ACCESS_WRITE:
1146 flags = MAP_SHARED;
1147 prot = PROT_READ | PROT_WRITE;
1148 break;
1149 case ACCESS_COPY:
1150 flags = MAP_PRIVATE;
1151 prot = PROT_READ | PROT_WRITE;
1152 break;
1153 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001154 /* map prot to access type */
1155 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1156 /* ACCESS_DEFAULT */
1157 }
1158 else if (prot & PROT_WRITE) {
1159 access = ACCESS_WRITE;
1160 }
1161 else {
1162 access = ACCESS_READ;
1163 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001164 break;
1165 default:
1166 return PyErr_Format(PyExc_ValueError,
1167 "mmap invalid access parameter.");
1168 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001169
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001170#ifdef __APPLE__
1171 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1172 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1173 if (fd != -1)
1174 (void)fcntl(fd, F_FULLFSYNC);
1175#endif
Neal Norwitzb5673922002-09-05 21:48:07 +00001176#ifdef HAVE_FSTAT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001177 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1178 if (map_size == 0) {
Jesus Cea941bfcc2012-09-10 00:27:55 +02001179 if (st.st_size == 0) {
1180 PyErr_SetString(PyExc_ValueError,
1181 "cannot mmap an empty file");
1182 return NULL;
1183 }
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001184 if (offset >= st.st_size) {
1185 PyErr_SetString(PyExc_ValueError,
1186 "mmap offset is greater than file size");
1187 return NULL;
1188 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001189 if (st.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001190 PyErr_SetString(PyExc_ValueError,
1191 "mmap length is too large");
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001192 return NULL;
1193 }
1194 map_size = (Py_ssize_t) (st.st_size - offset);
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001195 } else if (offset + (size_t)map_size > st.st_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001196 PyErr_SetString(PyExc_ValueError,
1197 "mmap length is greater than file size");
1198 return NULL;
1199 }
1200 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001201#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001202 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1203 if (m_obj == NULL) {return NULL;}
1204 m_obj->data = NULL;
1205 m_obj->size = (size_t) map_size;
1206 m_obj->pos = (size_t) 0;
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001207 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001208 m_obj->exports = 0;
1209 m_obj->offset = offset;
1210 if (fd == -1) {
1211 m_obj->fd = -1;
1212 /* Assume the caller wants to map anonymous memory.
1213 This is the same behaviour as Windows. mmap.mmap(-1, size)
1214 on both Windows and Unix map anonymous memory.
1215 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001216#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001217 /* BSD way to map anonymous memory */
1218 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001219#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001220 /* SVR4 method to map anonymous memory is to open /dev/zero */
Victor Stinnerdaf45552013-08-28 00:53:59 +02001221 fd = devzero = _Py_open("/dev/zero", O_RDWR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001222 if (devzero == -1) {
1223 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001224 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001225 return NULL;
1226 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001227#endif
Victor Stinnerdaf45552013-08-28 00:53:59 +02001228 }
1229 else {
1230 m_obj->fd = _Py_dup(fd);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001231 if (m_obj->fd == -1) {
1232 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001233 return NULL;
1234 }
1235 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001236
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001237 m_obj->data = mmap(NULL, map_size,
1238 prot, flags,
1239 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001240
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001241 if (devzero != -1) {
1242 close(devzero);
1243 }
1244
1245 if (m_obj->data == (char *)-1) {
1246 m_obj->data = NULL;
1247 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001248 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001249 return NULL;
1250 }
1251 m_obj->access = (access_mode)access;
1252 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001253}
1254#endif /* UNIX */
1255
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001256#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001257
1258/* A note on sizes and offsets: while the actual map size must hold in a
1259 Py_ssize_t, both the total file size and the start offset can be longer
1260 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1261*/
1262
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001263static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001264new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001265{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001266 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001267 PyObject *map_size_obj = NULL;
1268 Py_ssize_t map_size;
1269 PY_LONG_LONG offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001270 DWORD off_hi; /* upper 32 bits of offset */
1271 DWORD off_lo; /* lower 32 bits of offset */
1272 DWORD size_hi; /* upper 32 bits of size */
1273 DWORD size_lo; /* lower 32 bits of size */
1274 char *tagname = "";
1275 DWORD dwErr = 0;
1276 int fileno;
1277 HANDLE fh = 0;
1278 int access = (access_mode)ACCESS_DEFAULT;
1279 DWORD flProtect, dwDesiredAccess;
1280 static char *keywords[] = { "fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001281 "tagname",
1282 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001283
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001284 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001285 &fileno, &map_size_obj,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001286 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001287 return NULL;
1288 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001289
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001290 switch((access_mode)access) {
1291 case ACCESS_READ:
1292 flProtect = PAGE_READONLY;
1293 dwDesiredAccess = FILE_MAP_READ;
1294 break;
1295 case ACCESS_DEFAULT: case ACCESS_WRITE:
1296 flProtect = PAGE_READWRITE;
1297 dwDesiredAccess = FILE_MAP_WRITE;
1298 break;
1299 case ACCESS_COPY:
1300 flProtect = PAGE_WRITECOPY;
1301 dwDesiredAccess = FILE_MAP_COPY;
1302 break;
1303 default:
1304 return PyErr_Format(PyExc_ValueError,
1305 "mmap invalid access parameter.");
1306 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001307
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001308 map_size = _GetMapSize(map_size_obj, "size");
1309 if (map_size < 0)
1310 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001311 if (offset < 0) {
1312 PyErr_SetString(PyExc_OverflowError,
1313 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001314 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001315 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001316
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001317 /* assume -1 and 0 both mean invalid filedescriptor
1318 to 'anonymously' map memory.
1319 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1320 XXX: Should this code be added?
1321 if (fileno == 0)
1322 PyErr_WarnEx(PyExc_DeprecationWarning,
1323 "don't use 0 for anonymous memory",
1324 1);
1325 */
1326 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001327 /* Ensure that fileno is within the CRT's valid range */
1328 if (_PyVerify_fd(fileno) == 0) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001329 PyErr_SetFromErrno(PyExc_OSError);
Brian Curtinea47eaa2010-08-01 15:26:26 +00001330 return NULL;
1331 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001332 fh = (HANDLE)_get_osfhandle(fileno);
1333 if (fh==(HANDLE)-1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001334 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001335 return NULL;
1336 }
1337 /* Win9x appears to need us seeked to zero */
1338 lseek(fileno, 0, SEEK_SET);
1339 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001340
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001341 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1342 if (m_obj == NULL)
1343 return NULL;
1344 /* Set every field to an invalid marker, so we can safely
1345 destruct the object in the face of failure */
1346 m_obj->data = NULL;
1347 m_obj->file_handle = INVALID_HANDLE_VALUE;
1348 m_obj->map_handle = NULL;
1349 m_obj->tagname = NULL;
1350 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001351
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001352 if (fh) {
1353 /* It is necessary to duplicate the handle, so the
1354 Python code can close it on us */
1355 if (!DuplicateHandle(
1356 GetCurrentProcess(), /* source process handle */
1357 fh, /* handle to be duplicated */
1358 GetCurrentProcess(), /* target proc handle */
1359 (LPHANDLE)&m_obj->file_handle, /* result */
1360 0, /* access - ignored due to options value */
1361 FALSE, /* inherited by child processes? */
1362 DUPLICATE_SAME_ACCESS)) { /* options */
1363 dwErr = GetLastError();
1364 Py_DECREF(m_obj);
1365 PyErr_SetFromWindowsErr(dwErr);
1366 return NULL;
1367 }
1368 if (!map_size) {
1369 DWORD low,high;
1370 low = GetFileSize(fh, &high);
1371 /* low might just happen to have the value INVALID_FILE_SIZE;
1372 so we need to check the last error also. */
1373 if (low == INVALID_FILE_SIZE &&
1374 (dwErr = GetLastError()) != NO_ERROR) {
1375 Py_DECREF(m_obj);
1376 return PyErr_SetFromWindowsErr(dwErr);
1377 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001378
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001379 size = (((PY_LONG_LONG) high) << 32) + low;
Jesus Cea1f2799b2012-09-10 22:49:50 +02001380 if (size == 0) {
1381 PyErr_SetString(PyExc_ValueError,
1382 "cannot mmap an empty file");
Jesus Ceae8db3562012-09-10 22:58:07 +02001383 Py_DECREF(m_obj);
Jesus Cea1f2799b2012-09-10 22:49:50 +02001384 return NULL;
1385 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001386 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001387 PyErr_SetString(PyExc_ValueError,
1388 "mmap offset is greater than file size");
1389 Py_DECREF(m_obj);
1390 return NULL;
1391 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001392 if (size - offset > PY_SSIZE_T_MAX) {
1393 PyErr_SetString(PyExc_ValueError,
1394 "mmap length is too large");
1395 Py_DECREF(m_obj);
1396 return NULL;
1397 }
1398 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001399 } else {
1400 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001401 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001402 }
1403 }
1404 else {
1405 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001406 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001407 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001408
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001409 /* set the initial position */
1410 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001411
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001412 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001413 m_obj->exports = 0;
1414 /* set the tag name */
1415 if (tagname != NULL && *tagname != '\0') {
1416 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1417 if (m_obj->tagname == NULL) {
1418 PyErr_NoMemory();
1419 Py_DECREF(m_obj);
1420 return NULL;
1421 }
1422 strcpy(m_obj->tagname, tagname);
1423 }
1424 else
1425 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001426
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001427 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001428 size_hi = (DWORD)(size >> 32);
1429 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001430 off_hi = (DWORD)(offset >> 32);
1431 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001432 /* For files, it would be sufficient to pass 0 as size.
1433 For anonymous maps, we have to pass the size explicitly. */
1434 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1435 NULL,
1436 flProtect,
1437 size_hi,
1438 size_lo,
1439 m_obj->tagname);
1440 if (m_obj->map_handle != NULL) {
1441 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1442 dwDesiredAccess,
1443 off_hi,
1444 off_lo,
1445 m_obj->size);
1446 if (m_obj->data != NULL)
1447 return (PyObject *)m_obj;
1448 else {
1449 dwErr = GetLastError();
1450 CloseHandle(m_obj->map_handle);
1451 m_obj->map_handle = NULL;
1452 }
1453 } else
1454 dwErr = GetLastError();
1455 Py_DECREF(m_obj);
1456 PyErr_SetFromWindowsErr(dwErr);
1457 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001458}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001459#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001460
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001461static void
1462setint(PyObject *d, const char *name, long value)
1463{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001464 PyObject *o = PyLong_FromLong(value);
1465 if (o && PyDict_SetItemString(d, name, o) == 0) {
1466 Py_DECREF(o);
1467 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001468}
1469
Martin v. Löwis1a214512008-06-11 05:26:20 +00001470
1471static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001472 PyModuleDef_HEAD_INIT,
1473 "mmap",
1474 NULL,
1475 -1,
1476 NULL,
1477 NULL,
1478 NULL,
1479 NULL,
1480 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001481};
1482
Mark Hammond62b1ab12002-07-23 06:31:15 +00001483PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001484PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001485{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001486 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001487
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001488 if (PyType_Ready(&mmap_object_type) < 0)
1489 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001490
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001491 module = PyModule_Create(&mmapmodule);
1492 if (module == NULL)
1493 return NULL;
1494 dict = PyModule_GetDict(module);
1495 if (!dict)
1496 return NULL;
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001497 PyDict_SetItemString(dict, "error", PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001498 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001499#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001500 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001501#endif
1502#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001503 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001504#endif
1505#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001506 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001507#endif
1508
1509#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001510 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001511#endif
1512#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001513 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001514#endif
1515#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001516 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001517#endif
1518#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001519 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001520#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001521#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001522 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1523 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001524#endif
1525
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001526 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001527
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001528 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001529
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001530 setint(dict, "ACCESS_READ", ACCESS_READ);
1531 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1532 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1533 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001534}