blob: 63e93b730aa1c2d4e5c2f98f583f3501f46742e5 [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;
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 {
Steve Dowerf2f373f2015-02-21 08:44:05 -0800468 struct _Py_stat_struct buf;
469 if (-1 == _Py_fstat(self->fd, &buf)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200470 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000471 return NULL;
472 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000473#ifdef HAVE_LARGEFILE_SUPPORT
474 return PyLong_FromLongLong(buf.st_size);
475#else
476 return PyLong_FromLong(buf.st_size);
477#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000478 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000479#endif /* UNIX */
480}
481
482/* This assumes that you want the entire file mapped,
483 / and when recreating the map will make the new file
484 / have the new size
485 /
486 / Is this really necessary? This could easily be done
487 / from python by just closing and re-opening with the
488 / new size?
489 */
490
491static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000492mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000493 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000494{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000495 Py_ssize_t new_size;
496 CHECK_VALID(NULL);
497 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
498 !is_resizeable(self)) {
499 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000500#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000501 } else {
502 DWORD dwErrCode = 0;
503 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
504 /* First, unmap the file view */
505 UnmapViewOfFile(self->data);
506 self->data = NULL;
507 /* Close the mapping object */
508 CloseHandle(self->map_handle);
509 self->map_handle = NULL;
510 /* Move to the desired EOF position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000511 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
512 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
513 off_hi = (DWORD)(self->offset >> 32);
514 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000515 SetFilePointer(self->file_handle,
516 newSizeLow, &newSizeHigh, FILE_BEGIN);
517 /* Change the size of the file */
518 SetEndOfFile(self->file_handle);
519 /* Create another mapping object and remap the file view */
520 self->map_handle = CreateFileMapping(
521 self->file_handle,
522 NULL,
523 PAGE_READWRITE,
524 0,
525 0,
526 self->tagname);
527 if (self->map_handle != NULL) {
528 self->data = (char *) MapViewOfFile(self->map_handle,
529 FILE_MAP_WRITE,
530 off_hi,
531 off_lo,
532 new_size);
533 if (self->data != NULL) {
534 self->size = new_size;
535 Py_INCREF(Py_None);
536 return Py_None;
537 } else {
538 dwErrCode = GetLastError();
539 CloseHandle(self->map_handle);
540 self->map_handle = NULL;
541 }
542 } else {
543 dwErrCode = GetLastError();
544 }
545 PyErr_SetFromWindowsErr(dwErrCode);
546 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000547#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000548
549#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000550#ifndef HAVE_MREMAP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000551 } else {
552 PyErr_SetString(PyExc_SystemError,
553 "mmap: resizing not available--no mremap()");
554 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000555#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000556 } else {
557 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000558
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000559 if (ftruncate(self->fd, self->offset + new_size) == -1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200560 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000561 return NULL;
562 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000563
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000564#ifdef MREMAP_MAYMOVE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000565 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000566#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000567 #if defined(__NetBSD__)
568 newmap = mremap(self->data, self->size, self->data, new_size, 0);
569 #else
570 newmap = mremap(self->data, self->size, new_size, 0);
571 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000572#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000573 if (newmap == (void *)-1)
574 {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200575 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000576 return NULL;
577 }
578 self->data = newmap;
579 self->size = new_size;
580 Py_INCREF(Py_None);
581 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000582#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000583#endif /* UNIX */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000584 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000585}
586
587static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000588mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000589{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000590 CHECK_VALID(NULL);
591 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000592}
593
594static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000595mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000596{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000597 Py_ssize_t offset = 0;
598 Py_ssize_t size = self->size;
599 CHECK_VALID(NULL);
600 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
601 return NULL;
602 if ((size_t)(offset + size) > self->size) {
603 PyErr_SetString(PyExc_ValueError, "flush values out of range");
604 return NULL;
605 }
R. David Murraye194dd62010-10-18 01:14:06 +0000606
607 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
608 return PyLong_FromLong(0);
609
Christian Heimesaf98da12008-01-27 15:18:18 +0000610#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000611 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000612#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000613 /* XXX semantics of return value? */
614 /* XXX flags for msync? */
615 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200616 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000617 return NULL;
618 }
619 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000620#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000621 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
622 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000623#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000624}
625
626static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000627mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000628{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000629 Py_ssize_t dist;
630 int how=0;
631 CHECK_VALID(NULL);
632 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
633 return NULL;
634 else {
635 size_t where;
636 switch (how) {
637 case 0: /* relative to start */
638 if (dist < 0)
639 goto onoutofrange;
640 where = dist;
641 break;
642 case 1: /* relative to current position */
643 if ((Py_ssize_t)self->pos + dist < 0)
644 goto onoutofrange;
645 where = self->pos + dist;
646 break;
647 case 2: /* relative to end */
648 if ((Py_ssize_t)self->size + dist < 0)
649 goto onoutofrange;
650 where = self->size + dist;
651 break;
652 default:
653 PyErr_SetString(PyExc_ValueError, "unknown seek type");
654 return NULL;
655 }
656 if (where > self->size)
657 goto onoutofrange;
658 self->pos = where;
659 Py_INCREF(Py_None);
660 return Py_None;
661 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000662
Tim Peters5ebfd362001-11-13 23:11:19 +0000663 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000664 PyErr_SetString(PyExc_ValueError, "seek out of range");
665 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000666}
667
668static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000669mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000670{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000671 unsigned long dest, src, cnt;
672 CHECK_VALID(NULL);
673 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
674 !is_writable(self)) {
675 return NULL;
676 } else {
677 /* bounds check the values */
Brett Cannon5fac8af2011-06-06 20:22:56 -0700678 if ((cnt + dest) < cnt || (cnt + src) < cnt ||
679 src > self->size || (src + cnt) > self->size ||
680 dest > self->size || (dest + cnt) > self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000681 PyErr_SetString(PyExc_ValueError,
682 "source, destination, or count out of range");
683 return NULL;
684 }
685 memmove(self->data+dest, self->data+src, cnt);
686 Py_INCREF(Py_None);
687 return Py_None;
688 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000689}
690
Georg Brandl0bccc182010-08-01 14:50:00 +0000691static PyObject *
692mmap_closed_get(mmap_object *self)
693{
694#ifdef MS_WINDOWS
695 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
696#elif defined(UNIX)
697 return PyBool_FromLong(self->data == NULL ? 1 : 0);
698#endif
699}
700
701static PyObject *
702mmap__enter__method(mmap_object *self, PyObject *args)
703{
704 CHECK_VALID(NULL);
705
706 Py_INCREF(self);
707 return (PyObject *)self;
708}
709
710static PyObject *
711mmap__exit__method(PyObject *self, PyObject *args)
712{
Martin v. Löwisbd928fe2011-10-14 10:20:37 +0200713 _Py_IDENTIFIER(close);
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200714
715 return _PyObject_CallMethodId(self, &PyId_close, NULL);
Georg Brandl0bccc182010-08-01 14:50:00 +0000716}
717
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300718#ifdef MS_WINDOWS
719static PyObject *
720mmap__sizeof__method(mmap_object *self, void *unused)
721{
722 Py_ssize_t res;
723
724 res = sizeof(mmap_object);
725 if (self->tagname)
726 res += strlen(self->tagname) + 1;
727 return PyLong_FromSsize_t(res);
728}
729#endif
730
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000731static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000732 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
733 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
734 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
735 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
736 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
737 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
738 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
739 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
740 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
741 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
742 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
743 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
744 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
745 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000746 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
747 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300748#ifdef MS_WINDOWS
749 {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS},
750#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000751 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000752};
753
Georg Brandl0bccc182010-08-01 14:50:00 +0000754static PyGetSetDef mmap_object_getset[] = {
755 {"closed", (getter) mmap_closed_get, NULL, NULL},
756 {NULL}
757};
758
759
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000760/* Functions for treating an mmap'ed file as a buffer */
761
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000762static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000763mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000764{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000765 CHECK_VALID(-1);
766 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
767 (self->access == ACCESS_READ), flags) < 0)
768 return -1;
769 self->exports++;
770 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000771}
772
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000773static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000774mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000775{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000776 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000777}
778
Martin v. Löwis18e16552006-02-15 17:27:45 +0000779static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000780mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000781{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000782 CHECK_VALID(-1);
783 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000784}
785
786static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000787mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000788{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000789 CHECK_VALID(NULL);
790 if (i < 0 || (size_t)i >= self->size) {
791 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
792 return NULL;
793 }
794 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000795}
796
797static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000798mmap_subscript(mmap_object *self, PyObject *item)
799{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000800 CHECK_VALID(NULL);
801 if (PyIndex_Check(item)) {
802 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
803 if (i == -1 && PyErr_Occurred())
804 return NULL;
805 if (i < 0)
806 i += self->size;
807 if (i < 0 || (size_t)i >= self->size) {
808 PyErr_SetString(PyExc_IndexError,
809 "mmap index out of range");
810 return NULL;
811 }
812 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
813 }
814 else if (PySlice_Check(item)) {
815 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000816
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000817 if (PySlice_GetIndicesEx(item, self->size,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000818 &start, &stop, &step, &slicelen) < 0) {
819 return NULL;
820 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000821
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000822 if (slicelen <= 0)
823 return PyBytes_FromStringAndSize("", 0);
824 else if (step == 1)
825 return PyBytes_FromStringAndSize(self->data + start,
826 slicelen);
827 else {
828 char *result_buf = (char *)PyMem_Malloc(slicelen);
829 Py_ssize_t cur, i;
830 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000831
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000832 if (result_buf == NULL)
833 return PyErr_NoMemory();
834 for (cur = start, i = 0; i < slicelen;
835 cur += step, i++) {
836 result_buf[i] = self->data[cur];
837 }
838 result = PyBytes_FromStringAndSize(result_buf,
839 slicelen);
840 PyMem_Free(result_buf);
841 return result;
842 }
843 }
844 else {
845 PyErr_SetString(PyExc_TypeError,
846 "mmap indices must be integers");
847 return NULL;
848 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000849}
850
851static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000852mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000853{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000854 CHECK_VALID(NULL);
855 PyErr_SetString(PyExc_SystemError,
856 "mmaps don't support concatenation");
857 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000858}
859
860static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000861mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000862{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000863 CHECK_VALID(NULL);
864 PyErr_SetString(PyExc_SystemError,
865 "mmaps don't support repeat operation");
866 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000867}
868
869static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000870mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000871{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000872 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000873
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000874 CHECK_VALID(-1);
875 if (i < 0 || (size_t)i >= self->size) {
876 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
877 return -1;
878 }
879 if (v == NULL) {
880 PyErr_SetString(PyExc_TypeError,
881 "mmap object doesn't support item deletion");
882 return -1;
883 }
884 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
885 PyErr_SetString(PyExc_IndexError,
886 "mmap assignment must be length-1 bytes()");
887 return -1;
888 }
889 if (!is_writable(self))
890 return -1;
891 buf = PyBytes_AsString(v);
892 self->data[i] = buf[0];
893 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000894}
895
Thomas Woutersed03b412007-08-28 21:37:11 +0000896static int
897mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
898{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000899 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000900
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000901 if (!is_writable(self))
902 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000903
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000904 if (PyIndex_Check(item)) {
905 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
906 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000907
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000908 if (i == -1 && PyErr_Occurred())
909 return -1;
910 if (i < 0)
911 i += self->size;
912 if (i < 0 || (size_t)i >= self->size) {
913 PyErr_SetString(PyExc_IndexError,
914 "mmap index out of range");
915 return -1;
916 }
917 if (value == NULL) {
918 PyErr_SetString(PyExc_TypeError,
919 "mmap doesn't support item deletion");
920 return -1;
921 }
922 if (!PyIndex_Check(value)) {
923 PyErr_SetString(PyExc_TypeError,
924 "mmap item value must be an int");
925 return -1;
926 }
927 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
928 if (v == -1 && PyErr_Occurred())
929 return -1;
930 if (v < 0 || v > 255) {
931 PyErr_SetString(PyExc_ValueError,
932 "mmap item value must be "
933 "in range(0, 256)");
934 return -1;
935 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000936 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000937 return 0;
938 }
939 else if (PySlice_Check(item)) {
940 Py_ssize_t start, stop, step, slicelen;
941 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000942
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000943 if (PySlice_GetIndicesEx(item,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000944 self->size, &start, &stop,
945 &step, &slicelen) < 0) {
946 return -1;
947 }
948 if (value == NULL) {
949 PyErr_SetString(PyExc_TypeError,
950 "mmap object doesn't support slice deletion");
951 return -1;
952 }
953 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
954 return -1;
955 if (vbuf.len != slicelen) {
956 PyErr_SetString(PyExc_IndexError,
957 "mmap slice assignment is wrong size");
958 PyBuffer_Release(&vbuf);
959 return -1;
960 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000961
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000962 if (slicelen == 0) {
963 }
964 else if (step == 1) {
965 memcpy(self->data + start, vbuf.buf, slicelen);
966 }
967 else {
968 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000969
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000970 for (cur = start, i = 0;
971 i < slicelen;
972 cur += step, i++)
973 {
974 self->data[cur] = ((char *)vbuf.buf)[i];
975 }
976 }
977 PyBuffer_Release(&vbuf);
978 return 0;
979 }
980 else {
981 PyErr_SetString(PyExc_TypeError,
982 "mmap indices must be integer");
983 return -1;
984 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000985}
986
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000987static PySequenceMethods mmap_as_sequence = {
Stefan Krah23186992012-03-06 15:37:36 +0100988 (lenfunc)mmap_length, /*sq_length*/
989 (binaryfunc)mmap_concat, /*sq_concat*/
990 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
991 (ssizeargfunc)mmap_item, /*sq_item*/
992 0, /*sq_slice*/
993 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
994 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000995};
996
Thomas Woutersed03b412007-08-28 21:37:11 +0000997static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000998 (lenfunc)mmap_length,
999 (binaryfunc)mmap_subscript,
1000 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +00001001};
1002
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001003static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001004 (getbufferproc)mmap_buffer_getbuf,
1005 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001006};
1007
Georg Brandl86def6c2008-01-21 20:36:10 +00001008static PyObject *
1009new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1010
Christian Heimese1c98112008-01-21 11:20:28 +00001011PyDoc_STRVAR(mmap_doc,
1012"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1013\n\
1014Maps length bytes from the file specified by the file handle fileno,\n\
1015and returns a mmap object. If length is larger than the current size\n\
1016of the file, the file is extended to contain length bytes. If length\n\
1017is 0, the maximum length of the map is the current size of the file,\n\
1018except that if the file is empty Windows raises an exception (you cannot\n\
1019create an empty mapping on Windows).\n\
1020\n\
1021Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1022\n\
1023Maps length bytes from the file specified by the file descriptor fileno,\n\
1024and returns a mmap object. If length is 0, the maximum length of the map\n\
1025will be the current size of the file when mmap is called.\n\
1026flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1027private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +00001028object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +00001029that's shared with all other processes mapping the same areas of the file.\n\
1030The default value is MAP_SHARED.\n\
1031\n\
1032To map anonymous memory, pass -1 as the fileno (both versions).");
1033
1034
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001035static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001036 PyVarObject_HEAD_INIT(NULL, 0)
1037 "mmap.mmap", /* tp_name */
1038 sizeof(mmap_object), /* tp_size */
1039 0, /* tp_itemsize */
1040 /* methods */
1041 (destructor) mmap_object_dealloc, /* tp_dealloc */
1042 0, /* tp_print */
1043 0, /* tp_getattr */
1044 0, /* tp_setattr */
1045 0, /* tp_reserved */
1046 0, /* tp_repr */
1047 0, /* tp_as_number */
1048 &mmap_as_sequence, /*tp_as_sequence*/
1049 &mmap_as_mapping, /*tp_as_mapping*/
1050 0, /*tp_hash*/
1051 0, /*tp_call*/
1052 0, /*tp_str*/
1053 PyObject_GenericGetAttr, /*tp_getattro*/
1054 0, /*tp_setattro*/
1055 &mmap_as_buffer, /*tp_as_buffer*/
Stefan Krah23186992012-03-06 15:37:36 +01001056 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001057 mmap_doc, /*tp_doc*/
1058 0, /* tp_traverse */
1059 0, /* tp_clear */
1060 0, /* tp_richcompare */
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001061 offsetof(mmap_object, weakreflist), /* tp_weaklistoffset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001062 0, /* tp_iter */
1063 0, /* tp_iternext */
1064 mmap_object_methods, /* tp_methods */
1065 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001066 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001067 0, /* tp_base */
1068 0, /* tp_dict */
1069 0, /* tp_descr_get */
1070 0, /* tp_descr_set */
1071 0, /* tp_dictoffset */
Stefan Krah23186992012-03-06 15:37:36 +01001072 0, /* tp_init */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001073 PyType_GenericAlloc, /* tp_alloc */
1074 new_mmap_object, /* tp_new */
Stefan Krah23186992012-03-06 15:37:36 +01001075 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001076};
1077
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001078
1079/* extract the map size from the given PyObject
1080
Thomas Wouters7e474022000-07-16 12:04:32 +00001081 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001082 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001083static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001084_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001085{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001086 if (o == NULL)
1087 return 0;
1088 if (PyIndex_Check(o)) {
1089 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1090 if (i==-1 && PyErr_Occurred())
1091 return -1;
1092 if (i < 0) {
1093 PyErr_Format(PyExc_OverflowError,
1094 "memory mapped %s must be positive",
1095 param);
1096 return -1;
1097 }
1098 return i;
1099 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001100
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001101 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1102 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001103}
1104
Tim Petersec0a5f02006-02-16 23:47:20 +00001105#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001106#ifdef HAVE_LARGEFILE_SUPPORT
1107#define _Py_PARSE_OFF_T "L"
1108#else
1109#define _Py_PARSE_OFF_T "l"
1110#endif
1111
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001112static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001113new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001114{
Neal Norwitzb5673922002-09-05 21:48:07 +00001115#ifdef HAVE_FSTAT
Steve Dowerf2f373f2015-02-21 08:44:05 -08001116 struct _Py_stat_struct st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001117#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001118 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001119 PyObject *map_size_obj = NULL;
1120 Py_ssize_t map_size;
1121 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001122 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1123 int devzero = -1;
1124 int access = (int)ACCESS_DEFAULT;
1125 static char *keywords[] = {"fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001126 "flags", "prot",
1127 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001128
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001129 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001130 &fd, &map_size_obj, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001131 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001132 return NULL;
1133 map_size = _GetMapSize(map_size_obj, "size");
1134 if (map_size < 0)
1135 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001136 if (offset < 0) {
1137 PyErr_SetString(PyExc_OverflowError,
1138 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001139 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001140 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001141
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001142 if ((access != (int)ACCESS_DEFAULT) &&
1143 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1144 return PyErr_Format(PyExc_ValueError,
1145 "mmap can't specify both access and flags, prot.");
1146 switch ((access_mode)access) {
1147 case ACCESS_READ:
1148 flags = MAP_SHARED;
1149 prot = PROT_READ;
1150 break;
1151 case ACCESS_WRITE:
1152 flags = MAP_SHARED;
1153 prot = PROT_READ | PROT_WRITE;
1154 break;
1155 case ACCESS_COPY:
1156 flags = MAP_PRIVATE;
1157 prot = PROT_READ | PROT_WRITE;
1158 break;
1159 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001160 /* map prot to access type */
1161 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1162 /* ACCESS_DEFAULT */
1163 }
1164 else if (prot & PROT_WRITE) {
1165 access = ACCESS_WRITE;
1166 }
1167 else {
1168 access = ACCESS_READ;
1169 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001170 break;
1171 default:
1172 return PyErr_Format(PyExc_ValueError,
1173 "mmap invalid access parameter.");
1174 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001175
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001176#ifdef __APPLE__
1177 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1178 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1179 if (fd != -1)
1180 (void)fcntl(fd, F_FULLFSYNC);
1181#endif
Neal Norwitzb5673922002-09-05 21:48:07 +00001182#ifdef HAVE_FSTAT
Steve Dowerf2f373f2015-02-21 08:44:05 -08001183 if (fd != -1 && _Py_fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001184 if (map_size == 0) {
Jesus Cea941bfcc2012-09-10 00:27:55 +02001185 if (st.st_size == 0) {
1186 PyErr_SetString(PyExc_ValueError,
1187 "cannot mmap an empty file");
1188 return NULL;
1189 }
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001190 if (offset >= st.st_size) {
1191 PyErr_SetString(PyExc_ValueError,
1192 "mmap offset is greater than file size");
1193 return NULL;
1194 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001195 if (st.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001196 PyErr_SetString(PyExc_ValueError,
1197 "mmap length is too large");
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001198 return NULL;
1199 }
1200 map_size = (Py_ssize_t) (st.st_size - offset);
Victor Stinnere371b3d2015-03-18 15:04:34 +01001201 } else if (offset + map_size > st.st_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001202 PyErr_SetString(PyExc_ValueError,
1203 "mmap length is greater than file size");
1204 return NULL;
1205 }
1206 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001207#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001208 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1209 if (m_obj == NULL) {return NULL;}
1210 m_obj->data = NULL;
1211 m_obj->size = (size_t) map_size;
1212 m_obj->pos = (size_t) 0;
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001213 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001214 m_obj->exports = 0;
1215 m_obj->offset = offset;
1216 if (fd == -1) {
1217 m_obj->fd = -1;
1218 /* Assume the caller wants to map anonymous memory.
1219 This is the same behaviour as Windows. mmap.mmap(-1, size)
1220 on both Windows and Unix map anonymous memory.
1221 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001222#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001223 /* BSD way to map anonymous memory */
1224 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001225#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001226 /* SVR4 method to map anonymous memory is to open /dev/zero */
Victor Stinnerdaf45552013-08-28 00:53:59 +02001227 fd = devzero = _Py_open("/dev/zero", O_RDWR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001228 if (devzero == -1) {
1229 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001230 return NULL;
1231 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001232#endif
Victor Stinnerdaf45552013-08-28 00:53:59 +02001233 }
1234 else {
1235 m_obj->fd = _Py_dup(fd);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001236 if (m_obj->fd == -1) {
1237 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001238 return NULL;
1239 }
1240 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001241
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001242 m_obj->data = mmap(NULL, map_size,
1243 prot, flags,
1244 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001245
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001246 if (devzero != -1) {
1247 close(devzero);
1248 }
1249
1250 if (m_obj->data == (char *)-1) {
1251 m_obj->data = NULL;
1252 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001253 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001254 return NULL;
1255 }
1256 m_obj->access = (access_mode)access;
1257 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001258}
1259#endif /* UNIX */
1260
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001261#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001262
1263/* A note on sizes and offsets: while the actual map size must hold in a
1264 Py_ssize_t, both the total file size and the start offset can be longer
1265 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1266*/
1267
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001268static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001269new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001270{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001271 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001272 PyObject *map_size_obj = NULL;
1273 Py_ssize_t map_size;
1274 PY_LONG_LONG offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001275 DWORD off_hi; /* upper 32 bits of offset */
1276 DWORD off_lo; /* lower 32 bits of offset */
1277 DWORD size_hi; /* upper 32 bits of size */
1278 DWORD size_lo; /* lower 32 bits of size */
1279 char *tagname = "";
1280 DWORD dwErr = 0;
1281 int fileno;
1282 HANDLE fh = 0;
1283 int access = (access_mode)ACCESS_DEFAULT;
1284 DWORD flProtect, dwDesiredAccess;
1285 static char *keywords[] = { "fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001286 "tagname",
1287 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001288
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001289 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001290 &fileno, &map_size_obj,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001291 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001292 return NULL;
1293 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001294
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001295 switch((access_mode)access) {
1296 case ACCESS_READ:
1297 flProtect = PAGE_READONLY;
1298 dwDesiredAccess = FILE_MAP_READ;
1299 break;
1300 case ACCESS_DEFAULT: case ACCESS_WRITE:
1301 flProtect = PAGE_READWRITE;
1302 dwDesiredAccess = FILE_MAP_WRITE;
1303 break;
1304 case ACCESS_COPY:
1305 flProtect = PAGE_WRITECOPY;
1306 dwDesiredAccess = FILE_MAP_COPY;
1307 break;
1308 default:
1309 return PyErr_Format(PyExc_ValueError,
1310 "mmap invalid access parameter.");
1311 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001312
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001313 map_size = _GetMapSize(map_size_obj, "size");
1314 if (map_size < 0)
1315 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001316 if (offset < 0) {
1317 PyErr_SetString(PyExc_OverflowError,
1318 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001319 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001320 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001321
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001322 /* assume -1 and 0 both mean invalid filedescriptor
1323 to 'anonymously' map memory.
1324 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1325 XXX: Should this code be added?
1326 if (fileno == 0)
1327 PyErr_WarnEx(PyExc_DeprecationWarning,
1328 "don't use 0 for anonymous memory",
1329 1);
1330 */
1331 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001332 /* Ensure that fileno is within the CRT's valid range */
1333 if (_PyVerify_fd(fileno) == 0) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001334 PyErr_SetFromErrno(PyExc_OSError);
Brian Curtinea47eaa2010-08-01 15:26:26 +00001335 return NULL;
1336 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001337 fh = (HANDLE)_get_osfhandle(fileno);
1338 if (fh==(HANDLE)-1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001339 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001340 return NULL;
1341 }
1342 /* Win9x appears to need us seeked to zero */
1343 lseek(fileno, 0, SEEK_SET);
1344 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001345
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001346 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1347 if (m_obj == NULL)
1348 return NULL;
1349 /* Set every field to an invalid marker, so we can safely
1350 destruct the object in the face of failure */
1351 m_obj->data = NULL;
1352 m_obj->file_handle = INVALID_HANDLE_VALUE;
1353 m_obj->map_handle = NULL;
1354 m_obj->tagname = NULL;
1355 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001356
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001357 if (fh) {
1358 /* It is necessary to duplicate the handle, so the
1359 Python code can close it on us */
1360 if (!DuplicateHandle(
1361 GetCurrentProcess(), /* source process handle */
1362 fh, /* handle to be duplicated */
1363 GetCurrentProcess(), /* target proc handle */
1364 (LPHANDLE)&m_obj->file_handle, /* result */
1365 0, /* access - ignored due to options value */
1366 FALSE, /* inherited by child processes? */
1367 DUPLICATE_SAME_ACCESS)) { /* options */
1368 dwErr = GetLastError();
1369 Py_DECREF(m_obj);
1370 PyErr_SetFromWindowsErr(dwErr);
1371 return NULL;
1372 }
1373 if (!map_size) {
1374 DWORD low,high;
1375 low = GetFileSize(fh, &high);
1376 /* low might just happen to have the value INVALID_FILE_SIZE;
1377 so we need to check the last error also. */
1378 if (low == INVALID_FILE_SIZE &&
1379 (dwErr = GetLastError()) != NO_ERROR) {
1380 Py_DECREF(m_obj);
1381 return PyErr_SetFromWindowsErr(dwErr);
1382 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001383
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001384 size = (((PY_LONG_LONG) high) << 32) + low;
Jesus Cea1f2799b2012-09-10 22:49:50 +02001385 if (size == 0) {
1386 PyErr_SetString(PyExc_ValueError,
1387 "cannot mmap an empty file");
Jesus Ceae8db3562012-09-10 22:58:07 +02001388 Py_DECREF(m_obj);
Jesus Cea1f2799b2012-09-10 22:49:50 +02001389 return NULL;
1390 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001391 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001392 PyErr_SetString(PyExc_ValueError,
1393 "mmap offset is greater than file size");
1394 Py_DECREF(m_obj);
1395 return NULL;
1396 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001397 if (size - offset > PY_SSIZE_T_MAX) {
1398 PyErr_SetString(PyExc_ValueError,
1399 "mmap length is too large");
1400 Py_DECREF(m_obj);
1401 return NULL;
1402 }
1403 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001404 } 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 }
1408 }
1409 else {
1410 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001411 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001412 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001413
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001414 /* set the initial position */
1415 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001416
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001417 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001418 m_obj->exports = 0;
1419 /* set the tag name */
1420 if (tagname != NULL && *tagname != '\0') {
1421 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1422 if (m_obj->tagname == NULL) {
1423 PyErr_NoMemory();
1424 Py_DECREF(m_obj);
1425 return NULL;
1426 }
1427 strcpy(m_obj->tagname, tagname);
1428 }
1429 else
1430 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001431
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001432 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001433 size_hi = (DWORD)(size >> 32);
1434 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001435 off_hi = (DWORD)(offset >> 32);
1436 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001437 /* For files, it would be sufficient to pass 0 as size.
1438 For anonymous maps, we have to pass the size explicitly. */
1439 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1440 NULL,
1441 flProtect,
1442 size_hi,
1443 size_lo,
1444 m_obj->tagname);
1445 if (m_obj->map_handle != NULL) {
1446 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1447 dwDesiredAccess,
1448 off_hi,
1449 off_lo,
1450 m_obj->size);
1451 if (m_obj->data != NULL)
1452 return (PyObject *)m_obj;
1453 else {
1454 dwErr = GetLastError();
1455 CloseHandle(m_obj->map_handle);
1456 m_obj->map_handle = NULL;
1457 }
1458 } else
1459 dwErr = GetLastError();
1460 Py_DECREF(m_obj);
1461 PyErr_SetFromWindowsErr(dwErr);
1462 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001463}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001464#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001465
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001466static void
1467setint(PyObject *d, const char *name, long value)
1468{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001469 PyObject *o = PyLong_FromLong(value);
1470 if (o && PyDict_SetItemString(d, name, o) == 0) {
1471 Py_DECREF(o);
1472 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001473}
1474
Martin v. Löwis1a214512008-06-11 05:26:20 +00001475
1476static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001477 PyModuleDef_HEAD_INIT,
1478 "mmap",
1479 NULL,
1480 -1,
1481 NULL,
1482 NULL,
1483 NULL,
1484 NULL,
1485 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001486};
1487
Mark Hammond62b1ab12002-07-23 06:31:15 +00001488PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001489PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001490{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001491 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001492
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001493 if (PyType_Ready(&mmap_object_type) < 0)
1494 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001495
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001496 module = PyModule_Create(&mmapmodule);
1497 if (module == NULL)
1498 return NULL;
1499 dict = PyModule_GetDict(module);
1500 if (!dict)
1501 return NULL;
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001502 PyDict_SetItemString(dict, "error", PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001503 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001504#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001505 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001506#endif
1507#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001508 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001509#endif
1510#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001511 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001512#endif
1513
1514#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001515 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001516#endif
1517#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001518 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001519#endif
1520#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001521 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001522#endif
1523#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001524 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001525#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001526#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001527 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1528 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001529#endif
1530
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001531 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001532
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001533 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001534
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001535 setint(dict, "ACCESS_READ", ACCESS_READ);
1536 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1537 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1538 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001539}