blob: bb98a9942757b2fab3adb1982d4be82ffbcc1303 [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
Benjamin Petersonf6b5cad2015-08-02 12:15:30 -070027# ifdef HAVE_FCNTL_H
Victor Stinnera6cd0cf2011-05-02 01:05:37 +020028# include <fcntl.h>
Benjamin Petersonf6b5cad2015-08-02 12:15:30 -070029# endif /* HAVE_FCNTL_H */
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;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200304 Py_buffer view;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000305
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000306 CHECK_VALID(NULL);
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200307 if (!PyArg_ParseTuple(args, reverse ? "y*|nn:rfind" : "y*|nn:find",
308 &view, &start, &end)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000309 return NULL;
310 } else {
311 const char *p, *start_p, *end_p;
312 int sign = reverse ? -1 : 1;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200313 const char *needle = view.buf;
314 Py_ssize_t len = view.len;
Greg Stein834f4dd2001-05-14 09:32:26 +0000315
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000316 if (start < 0)
317 start += self->size;
318 if (start < 0)
319 start = 0;
320 else if ((size_t)start > self->size)
321 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000322
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000323 if (end < 0)
324 end += self->size;
325 if (end < 0)
326 end = 0;
327 else if ((size_t)end > self->size)
328 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000329
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000330 start_p = self->data + start;
331 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000332
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000333 for (p = (reverse ? end_p - len : start_p);
334 (p >= start_p) && (p + len <= end_p); p += sign) {
335 Py_ssize_t i;
336 for (i = 0; i < len && needle[i] == p[i]; ++i)
337 /* nothing */;
338 if (i == len) {
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200339 PyBuffer_Release(&view);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000340 return PyLong_FromSsize_t(p - self->data);
341 }
342 }
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200343 PyBuffer_Release(&view);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000344 return PyLong_FromLong(-1);
345 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000346}
347
Georg Brandlfceab5a2008-01-19 20:08:23 +0000348static PyObject *
349mmap_find_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000350 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000351{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000352 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000353}
354
355static PyObject *
356mmap_rfind_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000357 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000358{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000359 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000360}
361
Tim Petersec0a5f02006-02-16 23:47:20 +0000362static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000363is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000364{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000365 if (self->access != ACCESS_READ)
366 return 1;
367 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
368 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000369}
370
Tim Petersec0a5f02006-02-16 23:47:20 +0000371static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000372is_resizeable(mmap_object *self)
373{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000374 if (self->exports > 0) {
375 PyErr_SetString(PyExc_BufferError,
376 "mmap can't resize with extant buffers exported.");
377 return 0;
378 }
379 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
380 return 1;
381 PyErr_Format(PyExc_TypeError,
382 "mmap can't resize a readonly or copy-on-write memory map.");
383 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000384}
385
386
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000387static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000388mmap_write_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000389 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000390{
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200391 Py_buffer data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000392
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000393 CHECK_VALID(NULL);
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200394 if (!PyArg_ParseTuple(args, "y*:write", &data))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000395 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000396
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200397 if (!is_writable(self)) {
398 PyBuffer_Release(&data);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000399 return NULL;
400 }
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200401
402 if ((self->pos + data.len) > self->size) {
403 PyErr_SetString(PyExc_ValueError, "data out of range");
404 PyBuffer_Release(&data);
405 return NULL;
406 }
407 memcpy(self->data + self->pos, data.buf, data.len);
408 self->pos = self->pos + data.len;
409 PyBuffer_Release(&data);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000410 Py_INCREF(Py_None);
411 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000412}
413
414static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000415mmap_write_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000416 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000417{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000418 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000419
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000420 CHECK_VALID(NULL);
421 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
422 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000423
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000424 if (!is_writable(self))
425 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000426
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000427 if (self->pos < self->size) {
428 *(self->data+self->pos) = value;
429 self->pos += 1;
430 Py_INCREF(Py_None);
431 return Py_None;
432 }
433 else {
434 PyErr_SetString(PyExc_ValueError, "write byte out of range");
435 return NULL;
436 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000437}
Tim Petersec0a5f02006-02-16 23:47:20 +0000438
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000439static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000440mmap_size_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000441 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000442{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000443 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000444
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000445#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000446 if (self->file_handle != INVALID_HANDLE_VALUE) {
447 DWORD low,high;
448 PY_LONG_LONG size;
449 low = GetFileSize(self->file_handle, &high);
450 if (low == INVALID_FILE_SIZE) {
451 /* It might be that the function appears to have failed,
452 when indeed its size equals INVALID_FILE_SIZE */
453 DWORD error = GetLastError();
454 if (error != NO_ERROR)
455 return PyErr_SetFromWindowsErr(error);
456 }
457 if (!high && low < LONG_MAX)
458 return PyLong_FromLong((long)low);
459 size = (((PY_LONG_LONG)high)<<32) + low;
460 return PyLong_FromLongLong(size);
461 } else {
462 return PyLong_FromSsize_t(self->size);
463 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000464#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000465
466#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000467 {
Victor Stinnere134a7f2015-03-30 10:09:31 +0200468 struct _Py_stat_struct status;
469 if (_Py_fstat(self->fd, &status) == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000470 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000471#ifdef HAVE_LARGEFILE_SUPPORT
Victor Stinnere134a7f2015-03-30 10:09:31 +0200472 return PyLong_FromLongLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000473#else
Victor Stinnere134a7f2015-03-30 10:09:31 +0200474 return PyLong_FromLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000475#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000476 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000477#endif /* UNIX */
478}
479
480/* This assumes that you want the entire file mapped,
481 / and when recreating the map will make the new file
482 / have the new size
483 /
484 / Is this really necessary? This could easily be done
485 / from python by just closing and re-opening with the
486 / new size?
487 */
488
489static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000490mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000491 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000492{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000493 Py_ssize_t new_size;
494 CHECK_VALID(NULL);
495 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
496 !is_resizeable(self)) {
497 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000498#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000499 } else {
500 DWORD dwErrCode = 0;
501 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
502 /* First, unmap the file view */
503 UnmapViewOfFile(self->data);
504 self->data = NULL;
505 /* Close the mapping object */
506 CloseHandle(self->map_handle);
507 self->map_handle = NULL;
508 /* Move to the desired EOF position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000509 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
510 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
511 off_hi = (DWORD)(self->offset >> 32);
512 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000513 SetFilePointer(self->file_handle,
514 newSizeLow, &newSizeHigh, FILE_BEGIN);
515 /* Change the size of the file */
516 SetEndOfFile(self->file_handle);
517 /* Create another mapping object and remap the file view */
518 self->map_handle = CreateFileMapping(
519 self->file_handle,
520 NULL,
521 PAGE_READWRITE,
522 0,
523 0,
524 self->tagname);
525 if (self->map_handle != NULL) {
526 self->data = (char *) MapViewOfFile(self->map_handle,
527 FILE_MAP_WRITE,
528 off_hi,
529 off_lo,
530 new_size);
531 if (self->data != NULL) {
532 self->size = new_size;
533 Py_INCREF(Py_None);
534 return Py_None;
535 } else {
536 dwErrCode = GetLastError();
537 CloseHandle(self->map_handle);
538 self->map_handle = NULL;
539 }
540 } else {
541 dwErrCode = GetLastError();
542 }
543 PyErr_SetFromWindowsErr(dwErrCode);
544 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000545#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000546
547#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000548#ifndef HAVE_MREMAP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000549 } else {
550 PyErr_SetString(PyExc_SystemError,
551 "mmap: resizing not available--no mremap()");
552 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000553#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000554 } else {
555 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000556
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000557 if (ftruncate(self->fd, self->offset + new_size) == -1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200558 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000559 return NULL;
560 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000561
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000562#ifdef MREMAP_MAYMOVE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000563 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000564#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000565 #if defined(__NetBSD__)
566 newmap = mremap(self->data, self->size, self->data, new_size, 0);
567 #else
568 newmap = mremap(self->data, self->size, new_size, 0);
569 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000570#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000571 if (newmap == (void *)-1)
572 {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200573 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000574 return NULL;
575 }
576 self->data = newmap;
577 self->size = new_size;
578 Py_INCREF(Py_None);
579 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000580#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000581#endif /* UNIX */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000582 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000583}
584
585static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000586mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000587{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000588 CHECK_VALID(NULL);
589 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000590}
591
592static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000593mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000594{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000595 Py_ssize_t offset = 0;
596 Py_ssize_t size = self->size;
597 CHECK_VALID(NULL);
598 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
599 return NULL;
600 if ((size_t)(offset + size) > self->size) {
601 PyErr_SetString(PyExc_ValueError, "flush values out of range");
602 return NULL;
603 }
R. David Murraye194dd62010-10-18 01:14:06 +0000604
605 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
606 return PyLong_FromLong(0);
607
Christian Heimesaf98da12008-01-27 15:18:18 +0000608#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000609 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000610#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000611 /* XXX semantics of return value? */
612 /* XXX flags for msync? */
613 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200614 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000615 return NULL;
616 }
617 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000618#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000619 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
620 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000621#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000622}
623
624static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000625mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000626{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000627 Py_ssize_t dist;
628 int how=0;
629 CHECK_VALID(NULL);
630 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
631 return NULL;
632 else {
633 size_t where;
634 switch (how) {
635 case 0: /* relative to start */
636 if (dist < 0)
637 goto onoutofrange;
638 where = dist;
639 break;
640 case 1: /* relative to current position */
641 if ((Py_ssize_t)self->pos + dist < 0)
642 goto onoutofrange;
643 where = self->pos + dist;
644 break;
645 case 2: /* relative to end */
646 if ((Py_ssize_t)self->size + dist < 0)
647 goto onoutofrange;
648 where = self->size + dist;
649 break;
650 default:
651 PyErr_SetString(PyExc_ValueError, "unknown seek type");
652 return NULL;
653 }
654 if (where > self->size)
655 goto onoutofrange;
656 self->pos = where;
657 Py_INCREF(Py_None);
658 return Py_None;
659 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000660
Tim Peters5ebfd362001-11-13 23:11:19 +0000661 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000662 PyErr_SetString(PyExc_ValueError, "seek out of range");
663 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000664}
665
666static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000667mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000668{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000669 unsigned long dest, src, cnt;
670 CHECK_VALID(NULL);
671 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
672 !is_writable(self)) {
673 return NULL;
674 } else {
675 /* bounds check the values */
Brett Cannon5fac8af2011-06-06 20:22:56 -0700676 if ((cnt + dest) < cnt || (cnt + src) < cnt ||
677 src > self->size || (src + cnt) > self->size ||
678 dest > self->size || (dest + cnt) > self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000679 PyErr_SetString(PyExc_ValueError,
680 "source, destination, or count out of range");
681 return NULL;
682 }
683 memmove(self->data+dest, self->data+src, cnt);
684 Py_INCREF(Py_None);
685 return Py_None;
686 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000687}
688
Georg Brandl0bccc182010-08-01 14:50:00 +0000689static PyObject *
690mmap_closed_get(mmap_object *self)
691{
692#ifdef MS_WINDOWS
693 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
694#elif defined(UNIX)
695 return PyBool_FromLong(self->data == NULL ? 1 : 0);
696#endif
697}
698
699static PyObject *
700mmap__enter__method(mmap_object *self, PyObject *args)
701{
702 CHECK_VALID(NULL);
703
704 Py_INCREF(self);
705 return (PyObject *)self;
706}
707
708static PyObject *
709mmap__exit__method(PyObject *self, PyObject *args)
710{
Martin v. Löwisbd928fe2011-10-14 10:20:37 +0200711 _Py_IDENTIFIER(close);
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200712
713 return _PyObject_CallMethodId(self, &PyId_close, NULL);
Georg Brandl0bccc182010-08-01 14:50:00 +0000714}
715
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300716#ifdef MS_WINDOWS
717static PyObject *
718mmap__sizeof__method(mmap_object *self, void *unused)
719{
720 Py_ssize_t res;
721
Serhiy Storchaka5c4064e2015-12-19 20:05:25 +0200722 res = _PyObject_SIZE(Py_TYPE(self));
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300723 if (self->tagname)
724 res += strlen(self->tagname) + 1;
725 return PyLong_FromSsize_t(res);
726}
727#endif
728
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000729static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000730 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
731 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
732 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
733 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
734 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
735 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
736 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
737 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
738 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
739 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
740 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
741 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
742 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
743 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000744 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
745 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300746#ifdef MS_WINDOWS
747 {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS},
748#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000749 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000750};
751
Georg Brandl0bccc182010-08-01 14:50:00 +0000752static PyGetSetDef mmap_object_getset[] = {
753 {"closed", (getter) mmap_closed_get, NULL, NULL},
754 {NULL}
755};
756
757
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000758/* Functions for treating an mmap'ed file as a buffer */
759
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000760static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000761mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000762{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000763 CHECK_VALID(-1);
764 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
765 (self->access == ACCESS_READ), flags) < 0)
766 return -1;
767 self->exports++;
768 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000769}
770
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000771static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000772mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000773{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000774 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000775}
776
Martin v. Löwis18e16552006-02-15 17:27:45 +0000777static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000778mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000779{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000780 CHECK_VALID(-1);
781 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000782}
783
784static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000785mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000786{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000787 CHECK_VALID(NULL);
788 if (i < 0 || (size_t)i >= self->size) {
789 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
790 return NULL;
791 }
792 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000793}
794
795static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000796mmap_subscript(mmap_object *self, PyObject *item)
797{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000798 CHECK_VALID(NULL);
799 if (PyIndex_Check(item)) {
800 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
801 if (i == -1 && PyErr_Occurred())
802 return NULL;
803 if (i < 0)
804 i += self->size;
805 if (i < 0 || (size_t)i >= self->size) {
806 PyErr_SetString(PyExc_IndexError,
807 "mmap index out of range");
808 return NULL;
809 }
810 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
811 }
812 else if (PySlice_Check(item)) {
813 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000814
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000815 if (PySlice_GetIndicesEx(item, self->size,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000816 &start, &stop, &step, &slicelen) < 0) {
817 return NULL;
818 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000819
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000820 if (slicelen <= 0)
821 return PyBytes_FromStringAndSize("", 0);
822 else if (step == 1)
823 return PyBytes_FromStringAndSize(self->data + start,
824 slicelen);
825 else {
826 char *result_buf = (char *)PyMem_Malloc(slicelen);
827 Py_ssize_t cur, i;
828 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000829
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000830 if (result_buf == NULL)
831 return PyErr_NoMemory();
832 for (cur = start, i = 0; i < slicelen;
833 cur += step, i++) {
834 result_buf[i] = self->data[cur];
835 }
836 result = PyBytes_FromStringAndSize(result_buf,
837 slicelen);
838 PyMem_Free(result_buf);
839 return result;
840 }
841 }
842 else {
843 PyErr_SetString(PyExc_TypeError,
844 "mmap indices must be integers");
845 return NULL;
846 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000847}
848
849static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000850mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000851{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000852 CHECK_VALID(NULL);
853 PyErr_SetString(PyExc_SystemError,
854 "mmaps don't support concatenation");
855 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000856}
857
858static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000859mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000860{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000861 CHECK_VALID(NULL);
862 PyErr_SetString(PyExc_SystemError,
863 "mmaps don't support repeat operation");
864 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000865}
866
867static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000868mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000869{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000870 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000871
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000872 CHECK_VALID(-1);
873 if (i < 0 || (size_t)i >= self->size) {
874 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
875 return -1;
876 }
877 if (v == NULL) {
878 PyErr_SetString(PyExc_TypeError,
879 "mmap object doesn't support item deletion");
880 return -1;
881 }
882 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
883 PyErr_SetString(PyExc_IndexError,
884 "mmap assignment must be length-1 bytes()");
885 return -1;
886 }
887 if (!is_writable(self))
888 return -1;
889 buf = PyBytes_AsString(v);
890 self->data[i] = buf[0];
891 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000892}
893
Thomas Woutersed03b412007-08-28 21:37:11 +0000894static int
895mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
896{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000897 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000898
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000899 if (!is_writable(self))
900 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000901
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000902 if (PyIndex_Check(item)) {
903 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
904 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000905
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000906 if (i == -1 && PyErr_Occurred())
907 return -1;
908 if (i < 0)
909 i += self->size;
910 if (i < 0 || (size_t)i >= self->size) {
911 PyErr_SetString(PyExc_IndexError,
912 "mmap index out of range");
913 return -1;
914 }
915 if (value == NULL) {
916 PyErr_SetString(PyExc_TypeError,
917 "mmap doesn't support item deletion");
918 return -1;
919 }
920 if (!PyIndex_Check(value)) {
921 PyErr_SetString(PyExc_TypeError,
922 "mmap item value must be an int");
923 return -1;
924 }
925 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
926 if (v == -1 && PyErr_Occurred())
927 return -1;
928 if (v < 0 || v > 255) {
929 PyErr_SetString(PyExc_ValueError,
930 "mmap item value must be "
931 "in range(0, 256)");
932 return -1;
933 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000934 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000935 return 0;
936 }
937 else if (PySlice_Check(item)) {
938 Py_ssize_t start, stop, step, slicelen;
939 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000940
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000941 if (PySlice_GetIndicesEx(item,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000942 self->size, &start, &stop,
943 &step, &slicelen) < 0) {
944 return -1;
945 }
946 if (value == NULL) {
947 PyErr_SetString(PyExc_TypeError,
948 "mmap object doesn't support slice deletion");
949 return -1;
950 }
951 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
952 return -1;
953 if (vbuf.len != slicelen) {
954 PyErr_SetString(PyExc_IndexError,
955 "mmap slice assignment is wrong size");
956 PyBuffer_Release(&vbuf);
957 return -1;
958 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000959
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000960 if (slicelen == 0) {
961 }
962 else if (step == 1) {
963 memcpy(self->data + start, vbuf.buf, slicelen);
964 }
965 else {
966 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000967
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000968 for (cur = start, i = 0;
969 i < slicelen;
970 cur += step, i++)
971 {
972 self->data[cur] = ((char *)vbuf.buf)[i];
973 }
974 }
975 PyBuffer_Release(&vbuf);
976 return 0;
977 }
978 else {
979 PyErr_SetString(PyExc_TypeError,
980 "mmap indices must be integer");
981 return -1;
982 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000983}
984
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000985static PySequenceMethods mmap_as_sequence = {
Stefan Krah23186992012-03-06 15:37:36 +0100986 (lenfunc)mmap_length, /*sq_length*/
987 (binaryfunc)mmap_concat, /*sq_concat*/
988 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
989 (ssizeargfunc)mmap_item, /*sq_item*/
990 0, /*sq_slice*/
991 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
992 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000993};
994
Thomas Woutersed03b412007-08-28 21:37:11 +0000995static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000996 (lenfunc)mmap_length,
997 (binaryfunc)mmap_subscript,
998 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000999};
1000
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001001static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001002 (getbufferproc)mmap_buffer_getbuf,
1003 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001004};
1005
Georg Brandl86def6c2008-01-21 20:36:10 +00001006static PyObject *
1007new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1008
Christian Heimese1c98112008-01-21 11:20:28 +00001009PyDoc_STRVAR(mmap_doc,
1010"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1011\n\
1012Maps length bytes from the file specified by the file handle fileno,\n\
1013and returns a mmap object. If length is larger than the current size\n\
1014of the file, the file is extended to contain length bytes. If length\n\
1015is 0, the maximum length of the map is the current size of the file,\n\
1016except that if the file is empty Windows raises an exception (you cannot\n\
1017create an empty mapping on Windows).\n\
1018\n\
1019Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1020\n\
1021Maps length bytes from the file specified by the file descriptor fileno,\n\
1022and returns a mmap object. If length is 0, the maximum length of the map\n\
1023will be the current size of the file when mmap is called.\n\
1024flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1025private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +00001026object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +00001027that's shared with all other processes mapping the same areas of the file.\n\
1028The default value is MAP_SHARED.\n\
1029\n\
1030To map anonymous memory, pass -1 as the fileno (both versions).");
1031
1032
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001033static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001034 PyVarObject_HEAD_INIT(NULL, 0)
1035 "mmap.mmap", /* tp_name */
1036 sizeof(mmap_object), /* tp_size */
1037 0, /* tp_itemsize */
1038 /* methods */
1039 (destructor) mmap_object_dealloc, /* tp_dealloc */
1040 0, /* tp_print */
1041 0, /* tp_getattr */
1042 0, /* tp_setattr */
1043 0, /* tp_reserved */
1044 0, /* tp_repr */
1045 0, /* tp_as_number */
1046 &mmap_as_sequence, /*tp_as_sequence*/
1047 &mmap_as_mapping, /*tp_as_mapping*/
1048 0, /*tp_hash*/
1049 0, /*tp_call*/
1050 0, /*tp_str*/
1051 PyObject_GenericGetAttr, /*tp_getattro*/
1052 0, /*tp_setattro*/
1053 &mmap_as_buffer, /*tp_as_buffer*/
Stefan Krah23186992012-03-06 15:37:36 +01001054 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001055 mmap_doc, /*tp_doc*/
1056 0, /* tp_traverse */
1057 0, /* tp_clear */
1058 0, /* tp_richcompare */
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001059 offsetof(mmap_object, weakreflist), /* tp_weaklistoffset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001060 0, /* tp_iter */
1061 0, /* tp_iternext */
1062 mmap_object_methods, /* tp_methods */
1063 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001064 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001065 0, /* tp_base */
1066 0, /* tp_dict */
1067 0, /* tp_descr_get */
1068 0, /* tp_descr_set */
1069 0, /* tp_dictoffset */
Stefan Krah23186992012-03-06 15:37:36 +01001070 0, /* tp_init */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001071 PyType_GenericAlloc, /* tp_alloc */
1072 new_mmap_object, /* tp_new */
Stefan Krah23186992012-03-06 15:37:36 +01001073 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001074};
1075
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001076
1077/* extract the map size from the given PyObject
1078
Thomas Wouters7e474022000-07-16 12:04:32 +00001079 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001080 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001081static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001082_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001083{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001084 if (o == NULL)
1085 return 0;
1086 if (PyIndex_Check(o)) {
1087 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1088 if (i==-1 && PyErr_Occurred())
1089 return -1;
1090 if (i < 0) {
1091 PyErr_Format(PyExc_OverflowError,
1092 "memory mapped %s must be positive",
1093 param);
1094 return -1;
1095 }
1096 return i;
1097 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001098
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001099 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1100 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001101}
1102
Tim Petersec0a5f02006-02-16 23:47:20 +00001103#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001104#ifdef HAVE_LARGEFILE_SUPPORT
1105#define _Py_PARSE_OFF_T "L"
1106#else
1107#define _Py_PARSE_OFF_T "l"
1108#endif
1109
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001110static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001111new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001112{
Victor Stinnere134a7f2015-03-30 10:09:31 +02001113 struct _Py_stat_struct status;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001114 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001115 PyObject *map_size_obj = NULL;
1116 Py_ssize_t map_size;
1117 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001118 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1119 int devzero = -1;
1120 int access = (int)ACCESS_DEFAULT;
1121 static char *keywords[] = {"fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001122 "flags", "prot",
1123 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001124
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001125 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001126 &fd, &map_size_obj, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001127 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001128 return NULL;
1129 map_size = _GetMapSize(map_size_obj, "size");
1130 if (map_size < 0)
1131 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001132 if (offset < 0) {
1133 PyErr_SetString(PyExc_OverflowError,
1134 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001135 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001136 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001137
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001138 if ((access != (int)ACCESS_DEFAULT) &&
1139 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1140 return PyErr_Format(PyExc_ValueError,
1141 "mmap can't specify both access and flags, prot.");
1142 switch ((access_mode)access) {
1143 case ACCESS_READ:
1144 flags = MAP_SHARED;
1145 prot = PROT_READ;
1146 break;
1147 case ACCESS_WRITE:
1148 flags = MAP_SHARED;
1149 prot = PROT_READ | PROT_WRITE;
1150 break;
1151 case ACCESS_COPY:
1152 flags = MAP_PRIVATE;
1153 prot = PROT_READ | PROT_WRITE;
1154 break;
1155 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001156 /* map prot to access type */
1157 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1158 /* ACCESS_DEFAULT */
1159 }
1160 else if (prot & PROT_WRITE) {
1161 access = ACCESS_WRITE;
1162 }
1163 else {
1164 access = ACCESS_READ;
1165 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001166 break;
1167 default:
1168 return PyErr_Format(PyExc_ValueError,
1169 "mmap invalid access parameter.");
1170 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001171
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001172#ifdef __APPLE__
1173 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1174 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1175 if (fd != -1)
1176 (void)fcntl(fd, F_FULLFSYNC);
1177#endif
Victor Stinnere134a7f2015-03-30 10:09:31 +02001178 if (fd != -1 && _Py_fstat_noraise(fd, &status) == 0
1179 && S_ISREG(status.st_mode)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001180 if (map_size == 0) {
Victor Stinnere134a7f2015-03-30 10:09:31 +02001181 if (status.st_size == 0) {
Jesus Cea941bfcc2012-09-10 00:27:55 +02001182 PyErr_SetString(PyExc_ValueError,
1183 "cannot mmap an empty file");
1184 return NULL;
1185 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001186 if (offset >= status.st_size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001187 PyErr_SetString(PyExc_ValueError,
1188 "mmap offset is greater than file size");
1189 return NULL;
1190 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001191 if (status.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001192 PyErr_SetString(PyExc_ValueError,
1193 "mmap length is too large");
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001194 return NULL;
1195 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001196 map_size = (Py_ssize_t) (status.st_size - offset);
1197 } else if (offset + map_size > status.st_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001198 PyErr_SetString(PyExc_ValueError,
1199 "mmap length is greater than file size");
1200 return NULL;
1201 }
1202 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001203 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1204 if (m_obj == NULL) {return NULL;}
1205 m_obj->data = NULL;
1206 m_obj->size = (size_t) map_size;
1207 m_obj->pos = (size_t) 0;
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001208 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001209 m_obj->exports = 0;
1210 m_obj->offset = offset;
1211 if (fd == -1) {
1212 m_obj->fd = -1;
1213 /* Assume the caller wants to map anonymous memory.
1214 This is the same behaviour as Windows. mmap.mmap(-1, size)
1215 on both Windows and Unix map anonymous memory.
1216 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001217#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001218 /* BSD way to map anonymous memory */
1219 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001220#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001221 /* SVR4 method to map anonymous memory is to open /dev/zero */
Victor Stinnerdaf45552013-08-28 00:53:59 +02001222 fd = devzero = _Py_open("/dev/zero", O_RDWR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001223 if (devzero == -1) {
1224 Py_DECREF(m_obj);
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 */
Steve Dower8fc89802015-04-12 00:26:27 -04001328 if (!_PyVerify_fd(fileno)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001329 PyErr_SetFromErrno(PyExc_OSError);
Brian Curtinea47eaa2010-08-01 15:26:26 +00001330 return NULL;
1331 }
Steve Dower8fc89802015-04-12 00:26:27 -04001332 _Py_BEGIN_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001333 fh = (HANDLE)_get_osfhandle(fileno);
Steve Dower8fc89802015-04-12 00:26:27 -04001334 _Py_END_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001335 if (fh==(HANDLE)-1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001336 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001337 return NULL;
1338 }
1339 /* Win9x appears to need us seeked to zero */
1340 lseek(fileno, 0, SEEK_SET);
1341 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001342
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001343 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1344 if (m_obj == NULL)
1345 return NULL;
1346 /* Set every field to an invalid marker, so we can safely
1347 destruct the object in the face of failure */
1348 m_obj->data = NULL;
1349 m_obj->file_handle = INVALID_HANDLE_VALUE;
1350 m_obj->map_handle = NULL;
1351 m_obj->tagname = NULL;
1352 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001353
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001354 if (fh) {
1355 /* It is necessary to duplicate the handle, so the
1356 Python code can close it on us */
1357 if (!DuplicateHandle(
1358 GetCurrentProcess(), /* source process handle */
1359 fh, /* handle to be duplicated */
1360 GetCurrentProcess(), /* target proc handle */
1361 (LPHANDLE)&m_obj->file_handle, /* result */
1362 0, /* access - ignored due to options value */
1363 FALSE, /* inherited by child processes? */
1364 DUPLICATE_SAME_ACCESS)) { /* options */
1365 dwErr = GetLastError();
1366 Py_DECREF(m_obj);
1367 PyErr_SetFromWindowsErr(dwErr);
1368 return NULL;
1369 }
1370 if (!map_size) {
1371 DWORD low,high;
1372 low = GetFileSize(fh, &high);
1373 /* low might just happen to have the value INVALID_FILE_SIZE;
1374 so we need to check the last error also. */
1375 if (low == INVALID_FILE_SIZE &&
1376 (dwErr = GetLastError()) != NO_ERROR) {
1377 Py_DECREF(m_obj);
1378 return PyErr_SetFromWindowsErr(dwErr);
1379 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001380
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001381 size = (((PY_LONG_LONG) high) << 32) + low;
Jesus Cea1f2799b2012-09-10 22:49:50 +02001382 if (size == 0) {
1383 PyErr_SetString(PyExc_ValueError,
1384 "cannot mmap an empty file");
Jesus Ceae8db3562012-09-10 22:58:07 +02001385 Py_DECREF(m_obj);
Jesus Cea1f2799b2012-09-10 22:49:50 +02001386 return NULL;
1387 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001388 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001389 PyErr_SetString(PyExc_ValueError,
1390 "mmap offset is greater than file size");
1391 Py_DECREF(m_obj);
1392 return NULL;
1393 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001394 if (size - offset > PY_SSIZE_T_MAX) {
1395 PyErr_SetString(PyExc_ValueError,
1396 "mmap length is too large");
1397 Py_DECREF(m_obj);
1398 return NULL;
1399 }
1400 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001401 } else {
1402 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001403 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001404 }
1405 }
1406 else {
1407 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001408 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001409 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001410
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001411 /* set the initial position */
1412 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001413
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001414 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001415 m_obj->exports = 0;
1416 /* set the tag name */
1417 if (tagname != NULL && *tagname != '\0') {
1418 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1419 if (m_obj->tagname == NULL) {
1420 PyErr_NoMemory();
1421 Py_DECREF(m_obj);
1422 return NULL;
1423 }
1424 strcpy(m_obj->tagname, tagname);
1425 }
1426 else
1427 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001428
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001429 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001430 size_hi = (DWORD)(size >> 32);
1431 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001432 off_hi = (DWORD)(offset >> 32);
1433 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001434 /* For files, it would be sufficient to pass 0 as size.
1435 For anonymous maps, we have to pass the size explicitly. */
1436 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1437 NULL,
1438 flProtect,
1439 size_hi,
1440 size_lo,
1441 m_obj->tagname);
1442 if (m_obj->map_handle != NULL) {
1443 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1444 dwDesiredAccess,
1445 off_hi,
1446 off_lo,
1447 m_obj->size);
1448 if (m_obj->data != NULL)
1449 return (PyObject *)m_obj;
1450 else {
1451 dwErr = GetLastError();
1452 CloseHandle(m_obj->map_handle);
1453 m_obj->map_handle = NULL;
1454 }
1455 } else
1456 dwErr = GetLastError();
1457 Py_DECREF(m_obj);
1458 PyErr_SetFromWindowsErr(dwErr);
1459 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001460}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001461#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001462
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001463static void
1464setint(PyObject *d, const char *name, long value)
1465{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001466 PyObject *o = PyLong_FromLong(value);
1467 if (o && PyDict_SetItemString(d, name, o) == 0) {
1468 Py_DECREF(o);
1469 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001470}
1471
Martin v. Löwis1a214512008-06-11 05:26:20 +00001472
1473static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001474 PyModuleDef_HEAD_INIT,
1475 "mmap",
1476 NULL,
1477 -1,
1478 NULL,
1479 NULL,
1480 NULL,
1481 NULL,
1482 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001483};
1484
Mark Hammond62b1ab12002-07-23 06:31:15 +00001485PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001486PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001487{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001488 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001489
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001490 if (PyType_Ready(&mmap_object_type) < 0)
1491 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001492
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001493 module = PyModule_Create(&mmapmodule);
1494 if (module == NULL)
1495 return NULL;
1496 dict = PyModule_GetDict(module);
1497 if (!dict)
1498 return NULL;
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001499 PyDict_SetItemString(dict, "error", PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001500 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001501#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001502 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001503#endif
1504#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001505 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001506#endif
1507#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001508 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001509#endif
1510
1511#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001512 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001513#endif
1514#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001515 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001516#endif
1517#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001518 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001519#endif
1520#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001521 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001522#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001523#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001524 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1525 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001526#endif
1527
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001528 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001529
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001530 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001531
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001532 setint(dict, "ACCESS_READ", ACCESS_READ);
1533 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1534 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1535 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001536}