blob: b0015a5756f9f43ef1dbc88a59d8f123d2697bf6 [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
Benjamin Petersonaf580df2016-09-06 10:46:49 -070096 long long offset;
Antoine Pitrou97696cb2011-02-21 23:46:27 +000097#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;
Berker Peksag6282e652016-03-02 19:30:18 +0200392 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000393
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000394 CHECK_VALID(NULL);
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200395 if (!PyArg_ParseTuple(args, "y*:write", &data))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000396 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000397
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200398 if (!is_writable(self)) {
399 PyBuffer_Release(&data);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000400 return NULL;
401 }
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200402
403 if ((self->pos + data.len) > self->size) {
404 PyErr_SetString(PyExc_ValueError, "data out of range");
405 PyBuffer_Release(&data);
406 return NULL;
407 }
408 memcpy(self->data + self->pos, data.buf, data.len);
409 self->pos = self->pos + data.len;
Berker Peksag6282e652016-03-02 19:30:18 +0200410 result = PyLong_FromSsize_t(data.len);
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200411 PyBuffer_Release(&data);
Berker Peksag6282e652016-03-02 19:30:18 +0200412 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000413}
414
415static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000416mmap_write_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000417 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000418{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000419 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000420
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000421 CHECK_VALID(NULL);
422 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
423 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000424
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000425 if (!is_writable(self))
426 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000427
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000428 if (self->pos < self->size) {
429 *(self->data+self->pos) = value;
430 self->pos += 1;
431 Py_INCREF(Py_None);
432 return Py_None;
433 }
434 else {
435 PyErr_SetString(PyExc_ValueError, "write byte out of range");
436 return NULL;
437 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000438}
Tim Petersec0a5f02006-02-16 23:47:20 +0000439
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000440static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000441mmap_size_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000442 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000443{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000444 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000445
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000446#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000447 if (self->file_handle != INVALID_HANDLE_VALUE) {
448 DWORD low,high;
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700449 long long size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000450 low = GetFileSize(self->file_handle, &high);
451 if (low == INVALID_FILE_SIZE) {
452 /* It might be that the function appears to have failed,
453 when indeed its size equals INVALID_FILE_SIZE */
454 DWORD error = GetLastError();
455 if (error != NO_ERROR)
456 return PyErr_SetFromWindowsErr(error);
457 }
458 if (!high && low < LONG_MAX)
459 return PyLong_FromLong((long)low);
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700460 size = (((long long)high)<<32) + low;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000461 return PyLong_FromLongLong(size);
462 } else {
463 return PyLong_FromSsize_t(self->size);
464 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000465#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000466
467#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000468 {
Victor Stinnere134a7f2015-03-30 10:09:31 +0200469 struct _Py_stat_struct status;
470 if (_Py_fstat(self->fd, &status) == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000471 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000472#ifdef HAVE_LARGEFILE_SUPPORT
Victor Stinnere134a7f2015-03-30 10:09:31 +0200473 return PyLong_FromLongLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000474#else
Victor Stinnere134a7f2015-03-30 10:09:31 +0200475 return PyLong_FromLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000476#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000477 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000478#endif /* UNIX */
479}
480
481/* This assumes that you want the entire file mapped,
482 / and when recreating the map will make the new file
483 / have the new size
484 /
485 / Is this really necessary? This could easily be done
486 / from python by just closing and re-opening with the
487 / new size?
488 */
489
490static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000491mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000492 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000493{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000494 Py_ssize_t new_size;
495 CHECK_VALID(NULL);
496 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
497 !is_resizeable(self)) {
498 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000499#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000500 } else {
501 DWORD dwErrCode = 0;
502 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
503 /* First, unmap the file view */
504 UnmapViewOfFile(self->data);
505 self->data = NULL;
506 /* Close the mapping object */
507 CloseHandle(self->map_handle);
508 self->map_handle = NULL;
509 /* Move to the desired EOF position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000510 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
511 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
512 off_hi = (DWORD)(self->offset >> 32);
513 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000514 SetFilePointer(self->file_handle,
515 newSizeLow, &newSizeHigh, FILE_BEGIN);
516 /* Change the size of the file */
517 SetEndOfFile(self->file_handle);
518 /* Create another mapping object and remap the file view */
519 self->map_handle = CreateFileMapping(
520 self->file_handle,
521 NULL,
522 PAGE_READWRITE,
523 0,
524 0,
525 self->tagname);
526 if (self->map_handle != NULL) {
527 self->data = (char *) MapViewOfFile(self->map_handle,
528 FILE_MAP_WRITE,
529 off_hi,
530 off_lo,
531 new_size);
532 if (self->data != NULL) {
533 self->size = new_size;
534 Py_INCREF(Py_None);
535 return Py_None;
536 } else {
537 dwErrCode = GetLastError();
538 CloseHandle(self->map_handle);
539 self->map_handle = NULL;
540 }
541 } else {
542 dwErrCode = GetLastError();
543 }
544 PyErr_SetFromWindowsErr(dwErrCode);
545 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000546#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000547
548#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000549#ifndef HAVE_MREMAP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000550 } else {
551 PyErr_SetString(PyExc_SystemError,
552 "mmap: resizing not available--no mremap()");
553 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000554#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000555 } else {
556 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000557
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000558 if (ftruncate(self->fd, self->offset + new_size) == -1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200559 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000560 return NULL;
561 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000562
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000563#ifdef MREMAP_MAYMOVE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000564 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000565#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000566 #if defined(__NetBSD__)
567 newmap = mremap(self->data, self->size, self->data, new_size, 0);
568 #else
569 newmap = mremap(self->data, self->size, new_size, 0);
570 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000571#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000572 if (newmap == (void *)-1)
573 {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200574 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000575 return NULL;
576 }
577 self->data = newmap;
578 self->size = new_size;
579 Py_INCREF(Py_None);
580 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000581#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000582#endif /* UNIX */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000583 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000584}
585
586static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000587mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000588{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000589 CHECK_VALID(NULL);
590 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000591}
592
593static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000594mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000595{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000596 Py_ssize_t offset = 0;
597 Py_ssize_t size = self->size;
598 CHECK_VALID(NULL);
599 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
600 return NULL;
601 if ((size_t)(offset + size) > self->size) {
602 PyErr_SetString(PyExc_ValueError, "flush values out of range");
603 return NULL;
604 }
R. David Murraye194dd62010-10-18 01:14:06 +0000605
606 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
607 return PyLong_FromLong(0);
608
Christian Heimesaf98da12008-01-27 15:18:18 +0000609#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000610 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000611#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000612 /* XXX semantics of return value? */
613 /* XXX flags for msync? */
614 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200615 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000616 return NULL;
617 }
618 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000619#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000620 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
621 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000622#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000623}
624
625static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000626mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000627{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000628 Py_ssize_t dist;
629 int how=0;
630 CHECK_VALID(NULL);
631 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
632 return NULL;
633 else {
634 size_t where;
635 switch (how) {
636 case 0: /* relative to start */
637 if (dist < 0)
638 goto onoutofrange;
639 where = dist;
640 break;
641 case 1: /* relative to current position */
642 if ((Py_ssize_t)self->pos + dist < 0)
643 goto onoutofrange;
644 where = self->pos + dist;
645 break;
646 case 2: /* relative to end */
647 if ((Py_ssize_t)self->size + dist < 0)
648 goto onoutofrange;
649 where = self->size + dist;
650 break;
651 default:
652 PyErr_SetString(PyExc_ValueError, "unknown seek type");
653 return NULL;
654 }
655 if (where > self->size)
656 goto onoutofrange;
657 self->pos = where;
658 Py_INCREF(Py_None);
659 return Py_None;
660 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000661
Tim Peters5ebfd362001-11-13 23:11:19 +0000662 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000663 PyErr_SetString(PyExc_ValueError, "seek out of range");
664 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000665}
666
667static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000668mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000669{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000670 unsigned long dest, src, cnt;
671 CHECK_VALID(NULL);
672 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
673 !is_writable(self)) {
674 return NULL;
675 } else {
676 /* bounds check the values */
Brett Cannon5fac8af2011-06-06 20:22:56 -0700677 if ((cnt + dest) < cnt || (cnt + src) < cnt ||
678 src > self->size || (src + cnt) > self->size ||
679 dest > self->size || (dest + cnt) > self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000680 PyErr_SetString(PyExc_ValueError,
681 "source, destination, or count out of range");
682 return NULL;
683 }
684 memmove(self->data+dest, self->data+src, cnt);
685 Py_INCREF(Py_None);
686 return Py_None;
687 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000688}
689
Georg Brandl0bccc182010-08-01 14:50:00 +0000690static PyObject *
691mmap_closed_get(mmap_object *self)
692{
693#ifdef MS_WINDOWS
694 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
695#elif defined(UNIX)
696 return PyBool_FromLong(self->data == NULL ? 1 : 0);
697#endif
698}
699
700static PyObject *
701mmap__enter__method(mmap_object *self, PyObject *args)
702{
703 CHECK_VALID(NULL);
704
705 Py_INCREF(self);
706 return (PyObject *)self;
707}
708
709static PyObject *
710mmap__exit__method(PyObject *self, PyObject *args)
711{
Martin v. Löwisbd928fe2011-10-14 10:20:37 +0200712 _Py_IDENTIFIER(close);
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200713
714 return _PyObject_CallMethodId(self, &PyId_close, NULL);
Georg Brandl0bccc182010-08-01 14:50:00 +0000715}
716
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300717#ifdef MS_WINDOWS
718static PyObject *
719mmap__sizeof__method(mmap_object *self, void *unused)
720{
721 Py_ssize_t res;
722
Serhiy Storchaka5c4064e2015-12-19 20:05:25 +0200723 res = _PyObject_SIZE(Py_TYPE(self));
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300724 if (self->tagname)
725 res += strlen(self->tagname) + 1;
726 return PyLong_FromSsize_t(res);
727}
728#endif
729
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000730static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000731 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
732 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
733 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
734 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
735 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
736 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
737 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
738 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
739 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
740 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
741 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
742 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
743 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
744 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000745 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
746 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300747#ifdef MS_WINDOWS
748 {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS},
749#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000750 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000751};
752
Georg Brandl0bccc182010-08-01 14:50:00 +0000753static PyGetSetDef mmap_object_getset[] = {
754 {"closed", (getter) mmap_closed_get, NULL, NULL},
755 {NULL}
756};
757
758
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000759/* Functions for treating an mmap'ed file as a buffer */
760
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000761static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000762mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000763{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000764 CHECK_VALID(-1);
765 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
766 (self->access == ACCESS_READ), flags) < 0)
767 return -1;
768 self->exports++;
769 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000770}
771
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000772static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000773mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000774{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000775 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000776}
777
Martin v. Löwis18e16552006-02-15 17:27:45 +0000778static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000779mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000780{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000781 CHECK_VALID(-1);
782 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000783}
784
785static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000786mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000787{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000788 CHECK_VALID(NULL);
789 if (i < 0 || (size_t)i >= self->size) {
790 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
791 return NULL;
792 }
793 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000794}
795
796static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000797mmap_subscript(mmap_object *self, PyObject *item)
798{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000799 CHECK_VALID(NULL);
800 if (PyIndex_Check(item)) {
801 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
802 if (i == -1 && PyErr_Occurred())
803 return NULL;
804 if (i < 0)
805 i += self->size;
806 if (i < 0 || (size_t)i >= self->size) {
807 PyErr_SetString(PyExc_IndexError,
808 "mmap index out of range");
809 return NULL;
810 }
811 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
812 }
813 else if (PySlice_Check(item)) {
814 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000815
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000816 if (PySlice_GetIndicesEx(item, self->size,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000817 &start, &stop, &step, &slicelen) < 0) {
818 return NULL;
819 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000820
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000821 if (slicelen <= 0)
822 return PyBytes_FromStringAndSize("", 0);
823 else if (step == 1)
824 return PyBytes_FromStringAndSize(self->data + start,
825 slicelen);
826 else {
827 char *result_buf = (char *)PyMem_Malloc(slicelen);
828 Py_ssize_t cur, i;
829 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000830
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000831 if (result_buf == NULL)
832 return PyErr_NoMemory();
833 for (cur = start, i = 0; i < slicelen;
834 cur += step, i++) {
835 result_buf[i] = self->data[cur];
836 }
837 result = PyBytes_FromStringAndSize(result_buf,
838 slicelen);
839 PyMem_Free(result_buf);
840 return result;
841 }
842 }
843 else {
844 PyErr_SetString(PyExc_TypeError,
845 "mmap indices must be integers");
846 return NULL;
847 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000848}
849
850static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000851mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000852{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000853 CHECK_VALID(NULL);
854 PyErr_SetString(PyExc_SystemError,
855 "mmaps don't support concatenation");
856 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000857}
858
859static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000860mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000861{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000862 CHECK_VALID(NULL);
863 PyErr_SetString(PyExc_SystemError,
864 "mmaps don't support repeat operation");
865 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000866}
867
868static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000869mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000870{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000871 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000872
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000873 CHECK_VALID(-1);
874 if (i < 0 || (size_t)i >= self->size) {
875 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
876 return -1;
877 }
878 if (v == NULL) {
879 PyErr_SetString(PyExc_TypeError,
880 "mmap object doesn't support item deletion");
881 return -1;
882 }
883 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
884 PyErr_SetString(PyExc_IndexError,
885 "mmap assignment must be length-1 bytes()");
886 return -1;
887 }
888 if (!is_writable(self))
889 return -1;
890 buf = PyBytes_AsString(v);
891 self->data[i] = buf[0];
892 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000893}
894
Thomas Woutersed03b412007-08-28 21:37:11 +0000895static int
896mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
897{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000898 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000899
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000900 if (!is_writable(self))
901 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000902
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000903 if (PyIndex_Check(item)) {
904 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
905 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000906
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000907 if (i == -1 && PyErr_Occurred())
908 return -1;
909 if (i < 0)
910 i += self->size;
911 if (i < 0 || (size_t)i >= self->size) {
912 PyErr_SetString(PyExc_IndexError,
913 "mmap index out of range");
914 return -1;
915 }
916 if (value == NULL) {
917 PyErr_SetString(PyExc_TypeError,
918 "mmap doesn't support item deletion");
919 return -1;
920 }
921 if (!PyIndex_Check(value)) {
922 PyErr_SetString(PyExc_TypeError,
923 "mmap item value must be an int");
924 return -1;
925 }
926 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
927 if (v == -1 && PyErr_Occurred())
928 return -1;
929 if (v < 0 || v > 255) {
930 PyErr_SetString(PyExc_ValueError,
931 "mmap item value must be "
932 "in range(0, 256)");
933 return -1;
934 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000935 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000936 return 0;
937 }
938 else if (PySlice_Check(item)) {
939 Py_ssize_t start, stop, step, slicelen;
940 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000941
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000942 if (PySlice_GetIndicesEx(item,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000943 self->size, &start, &stop,
944 &step, &slicelen) < 0) {
945 return -1;
946 }
947 if (value == NULL) {
948 PyErr_SetString(PyExc_TypeError,
949 "mmap object doesn't support slice deletion");
950 return -1;
951 }
952 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
953 return -1;
954 if (vbuf.len != slicelen) {
955 PyErr_SetString(PyExc_IndexError,
956 "mmap slice assignment is wrong size");
957 PyBuffer_Release(&vbuf);
958 return -1;
959 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000960
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000961 if (slicelen == 0) {
962 }
963 else if (step == 1) {
964 memcpy(self->data + start, vbuf.buf, slicelen);
965 }
966 else {
967 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000968
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000969 for (cur = start, i = 0;
970 i < slicelen;
971 cur += step, i++)
972 {
973 self->data[cur] = ((char *)vbuf.buf)[i];
974 }
975 }
976 PyBuffer_Release(&vbuf);
977 return 0;
978 }
979 else {
980 PyErr_SetString(PyExc_TypeError,
981 "mmap indices must be integer");
982 return -1;
983 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000984}
985
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000986static PySequenceMethods mmap_as_sequence = {
Stefan Krah23186992012-03-06 15:37:36 +0100987 (lenfunc)mmap_length, /*sq_length*/
988 (binaryfunc)mmap_concat, /*sq_concat*/
989 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
990 (ssizeargfunc)mmap_item, /*sq_item*/
991 0, /*sq_slice*/
992 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
993 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000994};
995
Thomas Woutersed03b412007-08-28 21:37:11 +0000996static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000997 (lenfunc)mmap_length,
998 (binaryfunc)mmap_subscript,
999 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +00001000};
1001
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001002static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001003 (getbufferproc)mmap_buffer_getbuf,
1004 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001005};
1006
Georg Brandl86def6c2008-01-21 20:36:10 +00001007static PyObject *
1008new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1009
Christian Heimese1c98112008-01-21 11:20:28 +00001010PyDoc_STRVAR(mmap_doc,
1011"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1012\n\
1013Maps length bytes from the file specified by the file handle fileno,\n\
1014and returns a mmap object. If length is larger than the current size\n\
1015of the file, the file is extended to contain length bytes. If length\n\
1016is 0, the maximum length of the map is the current size of the file,\n\
1017except that if the file is empty Windows raises an exception (you cannot\n\
1018create an empty mapping on Windows).\n\
1019\n\
1020Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1021\n\
1022Maps length bytes from the file specified by the file descriptor fileno,\n\
1023and returns a mmap object. If length is 0, the maximum length of the map\n\
1024will be the current size of the file when mmap is called.\n\
1025flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1026private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +00001027object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +00001028that's shared with all other processes mapping the same areas of the file.\n\
1029The default value is MAP_SHARED.\n\
1030\n\
1031To map anonymous memory, pass -1 as the fileno (both versions).");
1032
1033
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001034static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001035 PyVarObject_HEAD_INIT(NULL, 0)
1036 "mmap.mmap", /* tp_name */
1037 sizeof(mmap_object), /* tp_size */
1038 0, /* tp_itemsize */
1039 /* methods */
1040 (destructor) mmap_object_dealloc, /* tp_dealloc */
1041 0, /* tp_print */
1042 0, /* tp_getattr */
1043 0, /* tp_setattr */
1044 0, /* tp_reserved */
1045 0, /* tp_repr */
1046 0, /* tp_as_number */
1047 &mmap_as_sequence, /*tp_as_sequence*/
1048 &mmap_as_mapping, /*tp_as_mapping*/
1049 0, /*tp_hash*/
1050 0, /*tp_call*/
1051 0, /*tp_str*/
1052 PyObject_GenericGetAttr, /*tp_getattro*/
1053 0, /*tp_setattro*/
1054 &mmap_as_buffer, /*tp_as_buffer*/
Stefan Krah23186992012-03-06 15:37:36 +01001055 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001056 mmap_doc, /*tp_doc*/
1057 0, /* tp_traverse */
1058 0, /* tp_clear */
1059 0, /* tp_richcompare */
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001060 offsetof(mmap_object, weakreflist), /* tp_weaklistoffset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001061 0, /* tp_iter */
1062 0, /* tp_iternext */
1063 mmap_object_methods, /* tp_methods */
1064 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001065 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001066 0, /* tp_base */
1067 0, /* tp_dict */
1068 0, /* tp_descr_get */
1069 0, /* tp_descr_set */
1070 0, /* tp_dictoffset */
Stefan Krah23186992012-03-06 15:37:36 +01001071 0, /* tp_init */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001072 PyType_GenericAlloc, /* tp_alloc */
1073 new_mmap_object, /* tp_new */
Stefan Krah23186992012-03-06 15:37:36 +01001074 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001075};
1076
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001077
1078/* extract the map size from the given PyObject
1079
Thomas Wouters7e474022000-07-16 12:04:32 +00001080 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001081 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001082static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001083_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001084{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001085 if (o == NULL)
1086 return 0;
1087 if (PyIndex_Check(o)) {
1088 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1089 if (i==-1 && PyErr_Occurred())
1090 return -1;
1091 if (i < 0) {
1092 PyErr_Format(PyExc_OverflowError,
1093 "memory mapped %s must be positive",
1094 param);
1095 return -1;
1096 }
1097 return i;
1098 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001099
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001100 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1101 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001102}
1103
Tim Petersec0a5f02006-02-16 23:47:20 +00001104#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001105#ifdef HAVE_LARGEFILE_SUPPORT
1106#define _Py_PARSE_OFF_T "L"
1107#else
1108#define _Py_PARSE_OFF_T "l"
1109#endif
1110
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001111static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001112new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001113{
Victor Stinnere134a7f2015-03-30 10:09:31 +02001114 struct _Py_stat_struct status;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001115 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001116 PyObject *map_size_obj = NULL;
1117 Py_ssize_t map_size;
1118 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001119 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1120 int devzero = -1;
1121 int access = (int)ACCESS_DEFAULT;
1122 static char *keywords[] = {"fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001123 "flags", "prot",
1124 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001125
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001126 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001127 &fd, &map_size_obj, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001128 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001129 return NULL;
1130 map_size = _GetMapSize(map_size_obj, "size");
1131 if (map_size < 0)
1132 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001133 if (offset < 0) {
1134 PyErr_SetString(PyExc_OverflowError,
1135 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001136 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001137 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001138
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001139 if ((access != (int)ACCESS_DEFAULT) &&
1140 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1141 return PyErr_Format(PyExc_ValueError,
1142 "mmap can't specify both access and flags, prot.");
1143 switch ((access_mode)access) {
1144 case ACCESS_READ:
1145 flags = MAP_SHARED;
1146 prot = PROT_READ;
1147 break;
1148 case ACCESS_WRITE:
1149 flags = MAP_SHARED;
1150 prot = PROT_READ | PROT_WRITE;
1151 break;
1152 case ACCESS_COPY:
1153 flags = MAP_PRIVATE;
1154 prot = PROT_READ | PROT_WRITE;
1155 break;
1156 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001157 /* map prot to access type */
1158 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1159 /* ACCESS_DEFAULT */
1160 }
1161 else if (prot & PROT_WRITE) {
1162 access = ACCESS_WRITE;
1163 }
1164 else {
1165 access = ACCESS_READ;
1166 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001167 break;
1168 default:
1169 return PyErr_Format(PyExc_ValueError,
1170 "mmap invalid access parameter.");
1171 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001172
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001173#ifdef __APPLE__
1174 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1175 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1176 if (fd != -1)
1177 (void)fcntl(fd, F_FULLFSYNC);
1178#endif
Victor Stinnere134a7f2015-03-30 10:09:31 +02001179 if (fd != -1 && _Py_fstat_noraise(fd, &status) == 0
1180 && S_ISREG(status.st_mode)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001181 if (map_size == 0) {
Victor Stinnere134a7f2015-03-30 10:09:31 +02001182 if (status.st_size == 0) {
Jesus Cea941bfcc2012-09-10 00:27:55 +02001183 PyErr_SetString(PyExc_ValueError,
1184 "cannot mmap an empty file");
1185 return NULL;
1186 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001187 if (offset >= status.st_size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001188 PyErr_SetString(PyExc_ValueError,
1189 "mmap offset is greater than file size");
1190 return NULL;
1191 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001192 if (status.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001193 PyErr_SetString(PyExc_ValueError,
1194 "mmap length is too large");
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001195 return NULL;
1196 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001197 map_size = (Py_ssize_t) (status.st_size - offset);
1198 } else if (offset + map_size > status.st_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001199 PyErr_SetString(PyExc_ValueError,
1200 "mmap length is greater than file size");
1201 return NULL;
1202 }
1203 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001204 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1205 if (m_obj == NULL) {return NULL;}
1206 m_obj->data = NULL;
1207 m_obj->size = (size_t) map_size;
1208 m_obj->pos = (size_t) 0;
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001209 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001210 m_obj->exports = 0;
1211 m_obj->offset = offset;
1212 if (fd == -1) {
1213 m_obj->fd = -1;
1214 /* Assume the caller wants to map anonymous memory.
1215 This is the same behaviour as Windows. mmap.mmap(-1, size)
1216 on both Windows and Unix map anonymous memory.
1217 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001218#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001219 /* BSD way to map anonymous memory */
1220 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001221#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001222 /* SVR4 method to map anonymous memory is to open /dev/zero */
Victor Stinnerdaf45552013-08-28 00:53:59 +02001223 fd = devzero = _Py_open("/dev/zero", O_RDWR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001224 if (devzero == -1) {
1225 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001226 return NULL;
1227 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001228#endif
Victor Stinnerdaf45552013-08-28 00:53:59 +02001229 }
1230 else {
1231 m_obj->fd = _Py_dup(fd);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001232 if (m_obj->fd == -1) {
1233 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001234 return NULL;
1235 }
1236 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001237
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001238 m_obj->data = mmap(NULL, map_size,
1239 prot, flags,
1240 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001241
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001242 if (devzero != -1) {
1243 close(devzero);
1244 }
1245
1246 if (m_obj->data == (char *)-1) {
1247 m_obj->data = NULL;
1248 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001249 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001250 return NULL;
1251 }
1252 m_obj->access = (access_mode)access;
1253 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001254}
1255#endif /* UNIX */
1256
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001257#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001258
1259/* A note on sizes and offsets: while the actual map size must hold in a
1260 Py_ssize_t, both the total file size and the start offset can be longer
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001261 than a Py_ssize_t, so we use long long which is always 64-bit.
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001262*/
1263
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001264static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001265new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001266{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001267 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001268 PyObject *map_size_obj = NULL;
1269 Py_ssize_t map_size;
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001270 long long offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001271 DWORD off_hi; /* upper 32 bits of offset */
1272 DWORD off_lo; /* lower 32 bits of offset */
1273 DWORD size_hi; /* upper 32 bits of size */
1274 DWORD size_lo; /* lower 32 bits of size */
1275 char *tagname = "";
1276 DWORD dwErr = 0;
1277 int fileno;
1278 HANDLE fh = 0;
1279 int access = (access_mode)ACCESS_DEFAULT;
1280 DWORD flProtect, dwDesiredAccess;
1281 static char *keywords[] = { "fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001282 "tagname",
1283 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001284
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001285 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001286 &fileno, &map_size_obj,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001287 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001288 return NULL;
1289 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001290
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001291 switch((access_mode)access) {
1292 case ACCESS_READ:
1293 flProtect = PAGE_READONLY;
1294 dwDesiredAccess = FILE_MAP_READ;
1295 break;
1296 case ACCESS_DEFAULT: case ACCESS_WRITE:
1297 flProtect = PAGE_READWRITE;
1298 dwDesiredAccess = FILE_MAP_WRITE;
1299 break;
1300 case ACCESS_COPY:
1301 flProtect = PAGE_WRITECOPY;
1302 dwDesiredAccess = FILE_MAP_COPY;
1303 break;
1304 default:
1305 return PyErr_Format(PyExc_ValueError,
1306 "mmap invalid access parameter.");
1307 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001308
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001309 map_size = _GetMapSize(map_size_obj, "size");
1310 if (map_size < 0)
1311 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001312 if (offset < 0) {
1313 PyErr_SetString(PyExc_OverflowError,
1314 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001315 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001316 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001317
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001318 /* assume -1 and 0 both mean invalid filedescriptor
1319 to 'anonymously' map memory.
1320 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1321 XXX: Should this code be added?
1322 if (fileno == 0)
1323 PyErr_WarnEx(PyExc_DeprecationWarning,
1324 "don't use 0 for anonymous memory",
1325 1);
1326 */
1327 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001328 /* Ensure that fileno is within the CRT's valid range */
Steve Dower8fc89802015-04-12 00:26:27 -04001329 if (!_PyVerify_fd(fileno)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001330 PyErr_SetFromErrno(PyExc_OSError);
Brian Curtinea47eaa2010-08-01 15:26:26 +00001331 return NULL;
1332 }
Steve Dower8fc89802015-04-12 00:26:27 -04001333 _Py_BEGIN_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001334 fh = (HANDLE)_get_osfhandle(fileno);
Steve Dower8fc89802015-04-12 00:26:27 -04001335 _Py_END_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001336 if (fh==(HANDLE)-1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001337 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001338 return NULL;
1339 }
1340 /* Win9x appears to need us seeked to zero */
1341 lseek(fileno, 0, SEEK_SET);
1342 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001343
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001344 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1345 if (m_obj == NULL)
1346 return NULL;
1347 /* Set every field to an invalid marker, so we can safely
1348 destruct the object in the face of failure */
1349 m_obj->data = NULL;
1350 m_obj->file_handle = INVALID_HANDLE_VALUE;
1351 m_obj->map_handle = NULL;
1352 m_obj->tagname = NULL;
1353 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001354
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001355 if (fh) {
1356 /* It is necessary to duplicate the handle, so the
1357 Python code can close it on us */
1358 if (!DuplicateHandle(
1359 GetCurrentProcess(), /* source process handle */
1360 fh, /* handle to be duplicated */
1361 GetCurrentProcess(), /* target proc handle */
1362 (LPHANDLE)&m_obj->file_handle, /* result */
1363 0, /* access - ignored due to options value */
1364 FALSE, /* inherited by child processes? */
1365 DUPLICATE_SAME_ACCESS)) { /* options */
1366 dwErr = GetLastError();
1367 Py_DECREF(m_obj);
1368 PyErr_SetFromWindowsErr(dwErr);
1369 return NULL;
1370 }
1371 if (!map_size) {
1372 DWORD low,high;
1373 low = GetFileSize(fh, &high);
1374 /* low might just happen to have the value INVALID_FILE_SIZE;
1375 so we need to check the last error also. */
1376 if (low == INVALID_FILE_SIZE &&
1377 (dwErr = GetLastError()) != NO_ERROR) {
1378 Py_DECREF(m_obj);
1379 return PyErr_SetFromWindowsErr(dwErr);
1380 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001381
Benjamin Petersonaf580df2016-09-06 10:46:49 -07001382 size = (((long long) high) << 32) + low;
Jesus Cea1f2799b2012-09-10 22:49:50 +02001383 if (size == 0) {
1384 PyErr_SetString(PyExc_ValueError,
1385 "cannot mmap an empty file");
Jesus Ceae8db3562012-09-10 22:58:07 +02001386 Py_DECREF(m_obj);
Jesus Cea1f2799b2012-09-10 22:49:50 +02001387 return NULL;
1388 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001389 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001390 PyErr_SetString(PyExc_ValueError,
1391 "mmap offset is greater than file size");
1392 Py_DECREF(m_obj);
1393 return NULL;
1394 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001395 if (size - offset > PY_SSIZE_T_MAX) {
1396 PyErr_SetString(PyExc_ValueError,
1397 "mmap length is too large");
1398 Py_DECREF(m_obj);
1399 return NULL;
1400 }
1401 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001402 } else {
1403 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001404 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001405 }
1406 }
1407 else {
1408 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001409 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001410 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001411
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001412 /* set the initial position */
1413 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001414
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001415 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001416 m_obj->exports = 0;
1417 /* set the tag name */
1418 if (tagname != NULL && *tagname != '\0') {
1419 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1420 if (m_obj->tagname == NULL) {
1421 PyErr_NoMemory();
1422 Py_DECREF(m_obj);
1423 return NULL;
1424 }
1425 strcpy(m_obj->tagname, tagname);
1426 }
1427 else
1428 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001429
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001430 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001431 size_hi = (DWORD)(size >> 32);
1432 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001433 off_hi = (DWORD)(offset >> 32);
1434 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001435 /* For files, it would be sufficient to pass 0 as size.
1436 For anonymous maps, we have to pass the size explicitly. */
1437 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1438 NULL,
1439 flProtect,
1440 size_hi,
1441 size_lo,
1442 m_obj->tagname);
1443 if (m_obj->map_handle != NULL) {
1444 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1445 dwDesiredAccess,
1446 off_hi,
1447 off_lo,
1448 m_obj->size);
1449 if (m_obj->data != NULL)
1450 return (PyObject *)m_obj;
1451 else {
1452 dwErr = GetLastError();
1453 CloseHandle(m_obj->map_handle);
1454 m_obj->map_handle = NULL;
1455 }
1456 } else
1457 dwErr = GetLastError();
1458 Py_DECREF(m_obj);
1459 PyErr_SetFromWindowsErr(dwErr);
1460 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001461}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001462#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001463
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001464static void
1465setint(PyObject *d, const char *name, long value)
1466{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001467 PyObject *o = PyLong_FromLong(value);
1468 if (o && PyDict_SetItemString(d, name, o) == 0) {
1469 Py_DECREF(o);
1470 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001471}
1472
Martin v. Löwis1a214512008-06-11 05:26:20 +00001473
1474static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001475 PyModuleDef_HEAD_INIT,
1476 "mmap",
1477 NULL,
1478 -1,
1479 NULL,
1480 NULL,
1481 NULL,
1482 NULL,
1483 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001484};
1485
Mark Hammond62b1ab12002-07-23 06:31:15 +00001486PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001487PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001488{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001489 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001490
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001491 if (PyType_Ready(&mmap_object_type) < 0)
1492 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001493
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001494 module = PyModule_Create(&mmapmodule);
1495 if (module == NULL)
1496 return NULL;
1497 dict = PyModule_GetDict(module);
1498 if (!dict)
1499 return NULL;
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001500 PyDict_SetItemString(dict, "error", PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001501 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001502#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001503 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001504#endif
1505#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001506 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001507#endif
1508#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001509 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001510#endif
1511
1512#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001513 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001514#endif
1515#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001516 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001517#endif
1518#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001519 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001520#endif
1521#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001522 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001523#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001524#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001525 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1526 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001527#endif
1528
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001529 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001530
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001531 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001532
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001533 setint(dict, "ACCESS_READ", ACCESS_READ);
1534 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1535 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1536 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001537}