blob: 6e2db6134ccb53b18a7134e35d857dafd3e17c15 [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;
Benjamin Petersoncd04db02016-10-05 21:45:48 -070093 Py_ssize_t size;
94 Py_ssize_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);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700213 if (self->pos >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000214 PyErr_SetString(PyExc_ValueError, "read byte out of range");
215 return NULL;
216 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700217 return PyLong_FromLong((unsigned char)self->data[self->pos++]);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000218}
219
220static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000221mmap_read_line_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000222 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000223{
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700224 Py_ssize_t remaining;
225 char *start, *eol;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000226 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000227
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000228 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000229
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700230 remaining = (self->pos < self->size) ? self->size - self->pos : 0;
231 if (!remaining)
232 return PyBytes_FromString("");
233 start = self->data + self->pos;
234 eol = memchr(start, '\n', remaining);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000235 if (!eol)
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700236 eol = self->data + self->size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000237 else
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700238 ++eol; /* advance past newline */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000239 result = PyBytes_FromStringAndSize(start, (eol - start));
240 self->pos += (eol - start);
241 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000242}
243
Charles-François Natali4dd453c2011-06-08 19:18:14 +0200244/* Basically the "n" format code with the ability to turn None into -1. */
245static int
246mmap_convert_ssize_t(PyObject *obj, void *result) {
247 Py_ssize_t limit;
248 if (obj == Py_None) {
249 limit = -1;
250 }
251 else if (PyNumber_Check(obj)) {
252 limit = PyNumber_AsSsize_t(obj, PyExc_OverflowError);
253 if (limit == -1 && PyErr_Occurred())
254 return 0;
255 }
256 else {
257 PyErr_Format(PyExc_TypeError,
258 "integer argument expected, got '%.200s'",
259 Py_TYPE(obj)->tp_name);
260 return 0;
261 }
262 *((Py_ssize_t *)result) = limit;
263 return 1;
264}
265
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000266static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000267mmap_read_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000268 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000269{
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700270 Py_ssize_t num_bytes, remaining;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000271 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000272
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000273 CHECK_VALID(NULL);
Charles-François Natali4dd453c2011-06-08 19:18:14 +0200274 if (!PyArg_ParseTuple(args, "|O&:read", mmap_convert_ssize_t, &num_bytes))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000275 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000276
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000277 /* silently 'adjust' out-of-range requests */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700278 remaining = (self->pos < self->size) ? self->size - self->pos : 0;
279 if (num_bytes < 0 || num_bytes > remaining)
280 num_bytes = remaining;
281 result = PyBytes_FromStringAndSize(&self->data[self->pos], num_bytes);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000282 self->pos += num_bytes;
283 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000284}
285
286static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000287mmap_gfind(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000288 PyObject *args,
289 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000290{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000291 Py_ssize_t start = self->pos;
292 Py_ssize_t end = self->size;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200293 Py_buffer view;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000294
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000295 CHECK_VALID(NULL);
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200296 if (!PyArg_ParseTuple(args, reverse ? "y*|nn:rfind" : "y*|nn:find",
297 &view, &start, &end)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000298 return NULL;
299 } else {
300 const char *p, *start_p, *end_p;
301 int sign = reverse ? -1 : 1;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200302 const char *needle = view.buf;
303 Py_ssize_t len = view.len;
Greg Stein834f4dd2001-05-14 09:32:26 +0000304
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000305 if (start < 0)
306 start += self->size;
307 if (start < 0)
308 start = 0;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700309 else if (start > self->size)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000310 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000311
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000312 if (end < 0)
313 end += self->size;
314 if (end < 0)
315 end = 0;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700316 else if (end > self->size)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000317 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000318
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000319 start_p = self->data + start;
320 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000321
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000322 for (p = (reverse ? end_p - len : start_p);
323 (p >= start_p) && (p + len <= end_p); p += sign) {
324 Py_ssize_t i;
325 for (i = 0; i < len && needle[i] == p[i]; ++i)
326 /* nothing */;
327 if (i == len) {
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200328 PyBuffer_Release(&view);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000329 return PyLong_FromSsize_t(p - self->data);
330 }
331 }
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200332 PyBuffer_Release(&view);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000333 return PyLong_FromLong(-1);
334 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000335}
336
Georg Brandlfceab5a2008-01-19 20:08:23 +0000337static PyObject *
338mmap_find_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000339 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000340{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000341 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000342}
343
344static PyObject *
345mmap_rfind_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000346 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000347{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000348 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000349}
350
Tim Petersec0a5f02006-02-16 23:47:20 +0000351static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000352is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000353{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000354 if (self->access != ACCESS_READ)
355 return 1;
356 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
357 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000358}
359
Tim Petersec0a5f02006-02-16 23:47:20 +0000360static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000361is_resizeable(mmap_object *self)
362{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000363 if (self->exports > 0) {
364 PyErr_SetString(PyExc_BufferError,
365 "mmap can't resize with extant buffers exported.");
366 return 0;
367 }
368 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
369 return 1;
370 PyErr_Format(PyExc_TypeError,
371 "mmap can't resize a readonly or copy-on-write memory map.");
372 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000373}
374
375
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000376static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000377mmap_write_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000378 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000379{
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200380 Py_buffer data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000381
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000382 CHECK_VALID(NULL);
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200383 if (!PyArg_ParseTuple(args, "y*:write", &data))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000384 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000385
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700386 if (!is_writable(self))
387 return NULL;
388
389 if (self->pos > self->size || self->size - self->pos < data.len) {
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200390 PyBuffer_Release(&data);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700391 PyErr_SetString(PyExc_ValueError, "data out of range");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000392 return NULL;
393 }
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200394
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700395 memcpy(&self->data[self->pos], data.buf, data.len);
396 self->pos += data.len;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200397 PyBuffer_Release(&data);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000398 Py_INCREF(Py_None);
399 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000400}
401
402static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000403mmap_write_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000404 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000405{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000406 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000407
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000408 CHECK_VALID(NULL);
409 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
410 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000411
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000412 if (!is_writable(self))
413 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000414
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000415 if (self->pos < self->size) {
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700416 self->data[self->pos++] = value;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000417 Py_INCREF(Py_None);
418 return Py_None;
419 }
420 else {
421 PyErr_SetString(PyExc_ValueError, "write byte out of range");
422 return NULL;
423 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000424}
Tim Petersec0a5f02006-02-16 23:47:20 +0000425
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000426static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000427mmap_size_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000428 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000429{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000430 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000431
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000432#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000433 if (self->file_handle != INVALID_HANDLE_VALUE) {
434 DWORD low,high;
435 PY_LONG_LONG size;
436 low = GetFileSize(self->file_handle, &high);
437 if (low == INVALID_FILE_SIZE) {
438 /* It might be that the function appears to have failed,
439 when indeed its size equals INVALID_FILE_SIZE */
440 DWORD error = GetLastError();
441 if (error != NO_ERROR)
442 return PyErr_SetFromWindowsErr(error);
443 }
444 if (!high && low < LONG_MAX)
445 return PyLong_FromLong((long)low);
446 size = (((PY_LONG_LONG)high)<<32) + low;
447 return PyLong_FromLongLong(size);
448 } else {
449 return PyLong_FromSsize_t(self->size);
450 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000451#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000452
453#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000454 {
Victor Stinnere134a7f2015-03-30 10:09:31 +0200455 struct _Py_stat_struct status;
456 if (_Py_fstat(self->fd, &status) == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000457 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000458#ifdef HAVE_LARGEFILE_SUPPORT
Victor Stinnere134a7f2015-03-30 10:09:31 +0200459 return PyLong_FromLongLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000460#else
Victor Stinnere134a7f2015-03-30 10:09:31 +0200461 return PyLong_FromLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000462#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000463 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000464#endif /* UNIX */
465}
466
467/* This assumes that you want the entire file mapped,
468 / and when recreating the map will make the new file
469 / have the new size
470 /
471 / Is this really necessary? This could easily be done
472 / from python by just closing and re-opening with the
473 / new size?
474 */
475
476static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000477mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000478 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000479{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000480 Py_ssize_t new_size;
481 CHECK_VALID(NULL);
482 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
483 !is_resizeable(self)) {
484 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700485 }
486 if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) {
487 PyErr_SetString(PyExc_ValueError, "new size out of range");
488 return NULL;
489 }
490
491 {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000492#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000493 DWORD dwErrCode = 0;
494 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
495 /* First, unmap the file view */
496 UnmapViewOfFile(self->data);
497 self->data = NULL;
498 /* Close the mapping object */
499 CloseHandle(self->map_handle);
500 self->map_handle = NULL;
501 /* Move to the desired EOF position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000502 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
503 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
504 off_hi = (DWORD)(self->offset >> 32);
505 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000506 SetFilePointer(self->file_handle,
507 newSizeLow, &newSizeHigh, FILE_BEGIN);
508 /* Change the size of the file */
509 SetEndOfFile(self->file_handle);
510 /* Create another mapping object and remap the file view */
511 self->map_handle = CreateFileMapping(
512 self->file_handle,
513 NULL,
514 PAGE_READWRITE,
515 0,
516 0,
517 self->tagname);
518 if (self->map_handle != NULL) {
519 self->data = (char *) MapViewOfFile(self->map_handle,
520 FILE_MAP_WRITE,
521 off_hi,
522 off_lo,
523 new_size);
524 if (self->data != NULL) {
525 self->size = new_size;
526 Py_INCREF(Py_None);
527 return Py_None;
528 } else {
529 dwErrCode = GetLastError();
530 CloseHandle(self->map_handle);
531 self->map_handle = NULL;
532 }
533 } else {
534 dwErrCode = GetLastError();
535 }
536 PyErr_SetFromWindowsErr(dwErrCode);
537 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000538#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000539
540#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000541#ifndef HAVE_MREMAP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000542 PyErr_SetString(PyExc_SystemError,
543 "mmap: resizing not available--no mremap()");
544 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000545#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000546 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000547
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700548 if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200549 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000550 return NULL;
551 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000552
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000553#ifdef MREMAP_MAYMOVE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000554 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000555#else
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700556#if defined(__NetBSD__)
557 newmap = mremap(self->data, self->size, self->data, new_size, 0);
558#else
559 newmap = mremap(self->data, self->size, new_size, 0);
560#endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000561#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000562 if (newmap == (void *)-1)
563 {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200564 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000565 return NULL;
566 }
567 self->data = newmap;
568 self->size = new_size;
569 Py_INCREF(Py_None);
570 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000571#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000572#endif /* UNIX */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000573 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000574}
575
576static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000577mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000578{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000579 CHECK_VALID(NULL);
580 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000581}
582
583static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000584mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000585{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000586 Py_ssize_t offset = 0;
587 Py_ssize_t size = self->size;
588 CHECK_VALID(NULL);
589 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
590 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700591 if (size < 0 || offset < 0 || self->size - offset < size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000592 PyErr_SetString(PyExc_ValueError, "flush values out of range");
593 return NULL;
594 }
R. David Murraye194dd62010-10-18 01:14:06 +0000595
596 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
597 return PyLong_FromLong(0);
598
Christian Heimesaf98da12008-01-27 15:18:18 +0000599#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000600 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000601#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000602 /* XXX semantics of return value? */
603 /* XXX flags for msync? */
604 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200605 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000606 return NULL;
607 }
608 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000609#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000610 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
611 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000612#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000613}
614
615static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000616mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000617{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000618 Py_ssize_t dist;
619 int how=0;
620 CHECK_VALID(NULL);
621 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
622 return NULL;
623 else {
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700624 Py_ssize_t where;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000625 switch (how) {
626 case 0: /* relative to start */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000627 where = dist;
628 break;
629 case 1: /* relative to current position */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700630 if (PY_SSIZE_T_MAX - self->pos < dist)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000631 goto onoutofrange;
632 where = self->pos + dist;
633 break;
634 case 2: /* relative to end */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700635 if (PY_SSIZE_T_MAX - self->size < dist)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000636 goto onoutofrange;
637 where = self->size + dist;
638 break;
639 default:
640 PyErr_SetString(PyExc_ValueError, "unknown seek type");
641 return NULL;
642 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700643 if (where > self->size || where < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000644 goto onoutofrange;
645 self->pos = where;
646 Py_INCREF(Py_None);
647 return Py_None;
648 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000649
Tim Peters5ebfd362001-11-13 23:11:19 +0000650 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000651 PyErr_SetString(PyExc_ValueError, "seek out of range");
652 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000653}
654
655static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000656mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000657{
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700658 Py_ssize_t dest, src, cnt;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000659 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700660 if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) ||
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000661 !is_writable(self)) {
662 return NULL;
663 } else {
664 /* bounds check the values */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700665 if (dest < 0 || src < 0 || cnt < 0)
666 goto bounds;
667 if (self->size - dest < cnt || self->size - src < cnt)
668 goto bounds;
669
670 memmove(&self->data[dest], &self->data[src], cnt);
671
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000672 Py_INCREF(Py_None);
673 return Py_None;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700674
675 bounds:
676 PyErr_SetString(PyExc_ValueError,
677 "source, destination, or count out of range");
678 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000679 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000680}
681
Georg Brandl0bccc182010-08-01 14:50:00 +0000682static PyObject *
683mmap_closed_get(mmap_object *self)
684{
685#ifdef MS_WINDOWS
686 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
687#elif defined(UNIX)
688 return PyBool_FromLong(self->data == NULL ? 1 : 0);
689#endif
690}
691
692static PyObject *
693mmap__enter__method(mmap_object *self, PyObject *args)
694{
695 CHECK_VALID(NULL);
696
697 Py_INCREF(self);
698 return (PyObject *)self;
699}
700
701static PyObject *
702mmap__exit__method(PyObject *self, PyObject *args)
703{
Martin v. Löwisbd928fe2011-10-14 10:20:37 +0200704 _Py_IDENTIFIER(close);
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200705
706 return _PyObject_CallMethodId(self, &PyId_close, NULL);
Georg Brandl0bccc182010-08-01 14:50:00 +0000707}
708
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300709#ifdef MS_WINDOWS
710static PyObject *
711mmap__sizeof__method(mmap_object *self, void *unused)
712{
713 Py_ssize_t res;
714
Serhiy Storchaka5c4064e2015-12-19 20:05:25 +0200715 res = _PyObject_SIZE(Py_TYPE(self));
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300716 if (self->tagname)
717 res += strlen(self->tagname) + 1;
718 return PyLong_FromSsize_t(res);
719}
720#endif
721
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000722static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000723 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
724 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
725 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
726 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
727 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
728 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
729 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
730 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
731 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
732 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
733 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
734 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
735 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
736 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000737 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
738 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300739#ifdef MS_WINDOWS
740 {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS},
741#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000742 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000743};
744
Georg Brandl0bccc182010-08-01 14:50:00 +0000745static PyGetSetDef mmap_object_getset[] = {
746 {"closed", (getter) mmap_closed_get, NULL, NULL},
747 {NULL}
748};
749
750
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000751/* Functions for treating an mmap'ed file as a buffer */
752
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000753static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000754mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000755{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000756 CHECK_VALID(-1);
757 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
758 (self->access == ACCESS_READ), flags) < 0)
759 return -1;
760 self->exports++;
761 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000762}
763
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000764static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000765mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000766{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000767 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000768}
769
Martin v. Löwis18e16552006-02-15 17:27:45 +0000770static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000771mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000772{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000773 CHECK_VALID(-1);
774 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000775}
776
777static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000778mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000779{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000780 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700781 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000782 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
783 return NULL;
784 }
785 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000786}
787
788static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000789mmap_subscript(mmap_object *self, PyObject *item)
790{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000791 CHECK_VALID(NULL);
792 if (PyIndex_Check(item)) {
793 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
794 if (i == -1 && PyErr_Occurred())
795 return NULL;
796 if (i < 0)
797 i += self->size;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700798 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000799 PyErr_SetString(PyExc_IndexError,
800 "mmap index out of range");
801 return NULL;
802 }
803 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
804 }
805 else if (PySlice_Check(item)) {
806 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000807
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000808 if (PySlice_GetIndicesEx(item, self->size,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000809 &start, &stop, &step, &slicelen) < 0) {
810 return NULL;
811 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000812
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000813 if (slicelen <= 0)
814 return PyBytes_FromStringAndSize("", 0);
815 else if (step == 1)
816 return PyBytes_FromStringAndSize(self->data + start,
817 slicelen);
818 else {
819 char *result_buf = (char *)PyMem_Malloc(slicelen);
820 Py_ssize_t cur, i;
821 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000822
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000823 if (result_buf == NULL)
824 return PyErr_NoMemory();
825 for (cur = start, i = 0; i < slicelen;
826 cur += step, i++) {
827 result_buf[i] = self->data[cur];
828 }
829 result = PyBytes_FromStringAndSize(result_buf,
830 slicelen);
831 PyMem_Free(result_buf);
832 return result;
833 }
834 }
835 else {
836 PyErr_SetString(PyExc_TypeError,
837 "mmap indices must be integers");
838 return NULL;
839 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000840}
841
842static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000843mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000844{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000845 CHECK_VALID(NULL);
846 PyErr_SetString(PyExc_SystemError,
847 "mmaps don't support concatenation");
848 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000849}
850
851static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000852mmap_repeat(mmap_object *self, Py_ssize_t n)
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 repeat operation");
857 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000858}
859
860static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000861mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000862{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000863 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000864
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000865 CHECK_VALID(-1);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700866 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000867 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
868 return -1;
869 }
870 if (v == NULL) {
871 PyErr_SetString(PyExc_TypeError,
872 "mmap object doesn't support item deletion");
873 return -1;
874 }
875 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
876 PyErr_SetString(PyExc_IndexError,
877 "mmap assignment must be length-1 bytes()");
878 return -1;
879 }
880 if (!is_writable(self))
881 return -1;
882 buf = PyBytes_AsString(v);
883 self->data[i] = buf[0];
884 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000885}
886
Thomas Woutersed03b412007-08-28 21:37:11 +0000887static int
888mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
889{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000890 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000891
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000892 if (!is_writable(self))
893 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000894
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000895 if (PyIndex_Check(item)) {
896 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
897 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000898
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000899 if (i == -1 && PyErr_Occurred())
900 return -1;
901 if (i < 0)
902 i += self->size;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700903 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000904 PyErr_SetString(PyExc_IndexError,
905 "mmap index out of range");
906 return -1;
907 }
908 if (value == NULL) {
909 PyErr_SetString(PyExc_TypeError,
910 "mmap doesn't support item deletion");
911 return -1;
912 }
913 if (!PyIndex_Check(value)) {
914 PyErr_SetString(PyExc_TypeError,
915 "mmap item value must be an int");
916 return -1;
917 }
918 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
919 if (v == -1 && PyErr_Occurred())
920 return -1;
921 if (v < 0 || v > 255) {
922 PyErr_SetString(PyExc_ValueError,
923 "mmap item value must be "
924 "in range(0, 256)");
925 return -1;
926 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000927 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000928 return 0;
929 }
930 else if (PySlice_Check(item)) {
931 Py_ssize_t start, stop, step, slicelen;
932 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000933
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000934 if (PySlice_GetIndicesEx(item,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000935 self->size, &start, &stop,
936 &step, &slicelen) < 0) {
937 return -1;
938 }
939 if (value == NULL) {
940 PyErr_SetString(PyExc_TypeError,
941 "mmap object doesn't support slice deletion");
942 return -1;
943 }
944 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
945 return -1;
946 if (vbuf.len != slicelen) {
947 PyErr_SetString(PyExc_IndexError,
948 "mmap slice assignment is wrong size");
949 PyBuffer_Release(&vbuf);
950 return -1;
951 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000952
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000953 if (slicelen == 0) {
954 }
955 else if (step == 1) {
956 memcpy(self->data + start, vbuf.buf, slicelen);
957 }
958 else {
959 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000960
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000961 for (cur = start, i = 0;
962 i < slicelen;
963 cur += step, i++)
964 {
965 self->data[cur] = ((char *)vbuf.buf)[i];
966 }
967 }
968 PyBuffer_Release(&vbuf);
969 return 0;
970 }
971 else {
972 PyErr_SetString(PyExc_TypeError,
973 "mmap indices must be integer");
974 return -1;
975 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000976}
977
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000978static PySequenceMethods mmap_as_sequence = {
Stefan Krah23186992012-03-06 15:37:36 +0100979 (lenfunc)mmap_length, /*sq_length*/
980 (binaryfunc)mmap_concat, /*sq_concat*/
981 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
982 (ssizeargfunc)mmap_item, /*sq_item*/
983 0, /*sq_slice*/
984 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
985 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000986};
987
Thomas Woutersed03b412007-08-28 21:37:11 +0000988static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000989 (lenfunc)mmap_length,
990 (binaryfunc)mmap_subscript,
991 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000992};
993
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000994static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000995 (getbufferproc)mmap_buffer_getbuf,
996 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000997};
998
Georg Brandl86def6c2008-01-21 20:36:10 +0000999static PyObject *
1000new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1001
Christian Heimese1c98112008-01-21 11:20:28 +00001002PyDoc_STRVAR(mmap_doc,
1003"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1004\n\
1005Maps length bytes from the file specified by the file handle fileno,\n\
1006and returns a mmap object. If length is larger than the current size\n\
1007of the file, the file is extended to contain length bytes. If length\n\
1008is 0, the maximum length of the map is the current size of the file,\n\
1009except that if the file is empty Windows raises an exception (you cannot\n\
1010create an empty mapping on Windows).\n\
1011\n\
1012Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1013\n\
1014Maps length bytes from the file specified by the file descriptor fileno,\n\
1015and returns a mmap object. If length is 0, the maximum length of the map\n\
1016will be the current size of the file when mmap is called.\n\
1017flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1018private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +00001019object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +00001020that's shared with all other processes mapping the same areas of the file.\n\
1021The default value is MAP_SHARED.\n\
1022\n\
1023To map anonymous memory, pass -1 as the fileno (both versions).");
1024
1025
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001026static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001027 PyVarObject_HEAD_INIT(NULL, 0)
1028 "mmap.mmap", /* tp_name */
1029 sizeof(mmap_object), /* tp_size */
1030 0, /* tp_itemsize */
1031 /* methods */
1032 (destructor) mmap_object_dealloc, /* tp_dealloc */
1033 0, /* tp_print */
1034 0, /* tp_getattr */
1035 0, /* tp_setattr */
1036 0, /* tp_reserved */
1037 0, /* tp_repr */
1038 0, /* tp_as_number */
1039 &mmap_as_sequence, /*tp_as_sequence*/
1040 &mmap_as_mapping, /*tp_as_mapping*/
1041 0, /*tp_hash*/
1042 0, /*tp_call*/
1043 0, /*tp_str*/
1044 PyObject_GenericGetAttr, /*tp_getattro*/
1045 0, /*tp_setattro*/
1046 &mmap_as_buffer, /*tp_as_buffer*/
Stefan Krah23186992012-03-06 15:37:36 +01001047 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001048 mmap_doc, /*tp_doc*/
1049 0, /* tp_traverse */
1050 0, /* tp_clear */
1051 0, /* tp_richcompare */
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001052 offsetof(mmap_object, weakreflist), /* tp_weaklistoffset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001053 0, /* tp_iter */
1054 0, /* tp_iternext */
1055 mmap_object_methods, /* tp_methods */
1056 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001057 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001058 0, /* tp_base */
1059 0, /* tp_dict */
1060 0, /* tp_descr_get */
1061 0, /* tp_descr_set */
1062 0, /* tp_dictoffset */
Stefan Krah23186992012-03-06 15:37:36 +01001063 0, /* tp_init */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001064 PyType_GenericAlloc, /* tp_alloc */
1065 new_mmap_object, /* tp_new */
Stefan Krah23186992012-03-06 15:37:36 +01001066 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001067};
1068
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001069
Tim Petersec0a5f02006-02-16 23:47:20 +00001070#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001071#ifdef HAVE_LARGEFILE_SUPPORT
1072#define _Py_PARSE_OFF_T "L"
1073#else
1074#define _Py_PARSE_OFF_T "l"
1075#endif
1076
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001077static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001078new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001079{
Victor Stinnere134a7f2015-03-30 10:09:31 +02001080 struct _Py_stat_struct status;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001081 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001082 Py_ssize_t map_size;
1083 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001084 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1085 int devzero = -1;
1086 int access = (int)ACCESS_DEFAULT;
1087 static char *keywords[] = {"fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001088 "flags", "prot",
1089 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001090
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001091 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords,
1092 &fd, &map_size, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001093 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001094 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001095 if (map_size < 0) {
1096 PyErr_SetString(PyExc_OverflowError,
1097 "memory mapped length must be postiive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001098 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001099 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001100 if (offset < 0) {
1101 PyErr_SetString(PyExc_OverflowError,
1102 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001103 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001104 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001105
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001106 if ((access != (int)ACCESS_DEFAULT) &&
1107 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1108 return PyErr_Format(PyExc_ValueError,
1109 "mmap can't specify both access and flags, prot.");
1110 switch ((access_mode)access) {
1111 case ACCESS_READ:
1112 flags = MAP_SHARED;
1113 prot = PROT_READ;
1114 break;
1115 case ACCESS_WRITE:
1116 flags = MAP_SHARED;
1117 prot = PROT_READ | PROT_WRITE;
1118 break;
1119 case ACCESS_COPY:
1120 flags = MAP_PRIVATE;
1121 prot = PROT_READ | PROT_WRITE;
1122 break;
1123 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001124 /* map prot to access type */
1125 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1126 /* ACCESS_DEFAULT */
1127 }
1128 else if (prot & PROT_WRITE) {
1129 access = ACCESS_WRITE;
1130 }
1131 else {
1132 access = ACCESS_READ;
1133 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001134 break;
1135 default:
1136 return PyErr_Format(PyExc_ValueError,
1137 "mmap invalid access parameter.");
1138 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001139
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001140#ifdef __APPLE__
1141 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1142 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1143 if (fd != -1)
1144 (void)fcntl(fd, F_FULLFSYNC);
1145#endif
Victor Stinnere134a7f2015-03-30 10:09:31 +02001146 if (fd != -1 && _Py_fstat_noraise(fd, &status) == 0
1147 && S_ISREG(status.st_mode)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001148 if (map_size == 0) {
Victor Stinnere134a7f2015-03-30 10:09:31 +02001149 if (status.st_size == 0) {
Jesus Cea941bfcc2012-09-10 00:27:55 +02001150 PyErr_SetString(PyExc_ValueError,
1151 "cannot mmap an empty file");
1152 return NULL;
1153 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001154 if (offset >= status.st_size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001155 PyErr_SetString(PyExc_ValueError,
1156 "mmap offset is greater than file size");
1157 return NULL;
1158 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001159 if (status.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001160 PyErr_SetString(PyExc_ValueError,
1161 "mmap length is too large");
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001162 return NULL;
1163 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001164 map_size = (Py_ssize_t) (status.st_size - offset);
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001165 } else if (offset > status.st_size || status.st_size - offset < map_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001166 PyErr_SetString(PyExc_ValueError,
1167 "mmap length is greater than file size");
1168 return NULL;
1169 }
1170 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001171 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1172 if (m_obj == NULL) {return NULL;}
1173 m_obj->data = NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001174 m_obj->size = map_size;
1175 m_obj->pos = 0;
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001176 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001177 m_obj->exports = 0;
1178 m_obj->offset = offset;
1179 if (fd == -1) {
1180 m_obj->fd = -1;
1181 /* Assume the caller wants to map anonymous memory.
1182 This is the same behaviour as Windows. mmap.mmap(-1, size)
1183 on both Windows and Unix map anonymous memory.
1184 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001185#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001186 /* BSD way to map anonymous memory */
1187 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001188#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001189 /* SVR4 method to map anonymous memory is to open /dev/zero */
Victor Stinnerdaf45552013-08-28 00:53:59 +02001190 fd = devzero = _Py_open("/dev/zero", O_RDWR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001191 if (devzero == -1) {
1192 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001193 return NULL;
1194 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001195#endif
Victor Stinnerdaf45552013-08-28 00:53:59 +02001196 }
1197 else {
1198 m_obj->fd = _Py_dup(fd);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001199 if (m_obj->fd == -1) {
1200 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001201 return NULL;
1202 }
1203 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001204
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001205 m_obj->data = mmap(NULL, map_size,
1206 prot, flags,
1207 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001208
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001209 if (devzero != -1) {
1210 close(devzero);
1211 }
1212
1213 if (m_obj->data == (char *)-1) {
1214 m_obj->data = NULL;
1215 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001216 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001217 return NULL;
1218 }
1219 m_obj->access = (access_mode)access;
1220 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001221}
1222#endif /* UNIX */
1223
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001224#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001225
1226/* A note on sizes and offsets: while the actual map size must hold in a
1227 Py_ssize_t, both the total file size and the start offset can be longer
1228 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1229*/
1230
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001231static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001232new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001233{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001234 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001235 Py_ssize_t map_size;
1236 PY_LONG_LONG offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001237 DWORD off_hi; /* upper 32 bits of offset */
1238 DWORD off_lo; /* lower 32 bits of offset */
1239 DWORD size_hi; /* upper 32 bits of size */
1240 DWORD size_lo; /* lower 32 bits of size */
1241 char *tagname = "";
1242 DWORD dwErr = 0;
1243 int fileno;
1244 HANDLE fh = 0;
1245 int access = (access_mode)ACCESS_DEFAULT;
1246 DWORD flProtect, dwDesiredAccess;
1247 static char *keywords[] = { "fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001248 "tagname",
1249 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001250
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001251 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords,
1252 &fileno, &map_size,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001253 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001254 return NULL;
1255 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001256
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001257 switch((access_mode)access) {
1258 case ACCESS_READ:
1259 flProtect = PAGE_READONLY;
1260 dwDesiredAccess = FILE_MAP_READ;
1261 break;
1262 case ACCESS_DEFAULT: case ACCESS_WRITE:
1263 flProtect = PAGE_READWRITE;
1264 dwDesiredAccess = FILE_MAP_WRITE;
1265 break;
1266 case ACCESS_COPY:
1267 flProtect = PAGE_WRITECOPY;
1268 dwDesiredAccess = FILE_MAP_COPY;
1269 break;
1270 default:
1271 return PyErr_Format(PyExc_ValueError,
1272 "mmap invalid access parameter.");
1273 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001274
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001275 if (map_size < 0) {
1276 PyErr_SetString(PyExc_OverflowError,
1277 "memory mapped length must be postiive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001278 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001279 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001280 if (offset < 0) {
1281 PyErr_SetString(PyExc_OverflowError,
1282 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001283 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001284 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001285
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001286 /* assume -1 and 0 both mean invalid filedescriptor
1287 to 'anonymously' map memory.
1288 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1289 XXX: Should this code be added?
1290 if (fileno == 0)
1291 PyErr_WarnEx(PyExc_DeprecationWarning,
1292 "don't use 0 for anonymous memory",
1293 1);
1294 */
1295 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001296 /* Ensure that fileno is within the CRT's valid range */
Steve Dower8fc89802015-04-12 00:26:27 -04001297 if (!_PyVerify_fd(fileno)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001298 PyErr_SetFromErrno(PyExc_OSError);
Brian Curtinea47eaa2010-08-01 15:26:26 +00001299 return NULL;
1300 }
Steve Dower8fc89802015-04-12 00:26:27 -04001301 _Py_BEGIN_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001302 fh = (HANDLE)_get_osfhandle(fileno);
Steve Dower8fc89802015-04-12 00:26:27 -04001303 _Py_END_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001304 if (fh==(HANDLE)-1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001305 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001306 return NULL;
1307 }
1308 /* Win9x appears to need us seeked to zero */
1309 lseek(fileno, 0, SEEK_SET);
1310 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001311
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001312 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1313 if (m_obj == NULL)
1314 return NULL;
1315 /* Set every field to an invalid marker, so we can safely
1316 destruct the object in the face of failure */
1317 m_obj->data = NULL;
1318 m_obj->file_handle = INVALID_HANDLE_VALUE;
1319 m_obj->map_handle = NULL;
1320 m_obj->tagname = NULL;
1321 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001322
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001323 if (fh) {
1324 /* It is necessary to duplicate the handle, so the
1325 Python code can close it on us */
1326 if (!DuplicateHandle(
1327 GetCurrentProcess(), /* source process handle */
1328 fh, /* handle to be duplicated */
1329 GetCurrentProcess(), /* target proc handle */
1330 (LPHANDLE)&m_obj->file_handle, /* result */
1331 0, /* access - ignored due to options value */
1332 FALSE, /* inherited by child processes? */
1333 DUPLICATE_SAME_ACCESS)) { /* options */
1334 dwErr = GetLastError();
1335 Py_DECREF(m_obj);
1336 PyErr_SetFromWindowsErr(dwErr);
1337 return NULL;
1338 }
1339 if (!map_size) {
1340 DWORD low,high;
1341 low = GetFileSize(fh, &high);
1342 /* low might just happen to have the value INVALID_FILE_SIZE;
1343 so we need to check the last error also. */
1344 if (low == INVALID_FILE_SIZE &&
1345 (dwErr = GetLastError()) != NO_ERROR) {
1346 Py_DECREF(m_obj);
1347 return PyErr_SetFromWindowsErr(dwErr);
1348 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001349
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001350 size = (((PY_LONG_LONG) high) << 32) + low;
Jesus Cea1f2799b2012-09-10 22:49:50 +02001351 if (size == 0) {
1352 PyErr_SetString(PyExc_ValueError,
1353 "cannot mmap an empty file");
Jesus Ceae8db3562012-09-10 22:58:07 +02001354 Py_DECREF(m_obj);
Jesus Cea1f2799b2012-09-10 22:49:50 +02001355 return NULL;
1356 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001357 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001358 PyErr_SetString(PyExc_ValueError,
1359 "mmap offset is greater than file size");
1360 Py_DECREF(m_obj);
1361 return NULL;
1362 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001363 if (size - offset > PY_SSIZE_T_MAX) {
1364 PyErr_SetString(PyExc_ValueError,
1365 "mmap length is too large");
1366 Py_DECREF(m_obj);
1367 return NULL;
1368 }
1369 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001370 } else {
1371 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001372 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001373 }
1374 }
1375 else {
1376 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001377 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001378 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001379
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001380 /* set the initial position */
1381 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001382
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001383 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001384 m_obj->exports = 0;
1385 /* set the tag name */
1386 if (tagname != NULL && *tagname != '\0') {
1387 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1388 if (m_obj->tagname == NULL) {
1389 PyErr_NoMemory();
1390 Py_DECREF(m_obj);
1391 return NULL;
1392 }
1393 strcpy(m_obj->tagname, tagname);
1394 }
1395 else
1396 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001397
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001398 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001399 size_hi = (DWORD)(size >> 32);
1400 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001401 off_hi = (DWORD)(offset >> 32);
1402 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001403 /* For files, it would be sufficient to pass 0 as size.
1404 For anonymous maps, we have to pass the size explicitly. */
1405 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1406 NULL,
1407 flProtect,
1408 size_hi,
1409 size_lo,
1410 m_obj->tagname);
1411 if (m_obj->map_handle != NULL) {
1412 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1413 dwDesiredAccess,
1414 off_hi,
1415 off_lo,
1416 m_obj->size);
1417 if (m_obj->data != NULL)
1418 return (PyObject *)m_obj;
1419 else {
1420 dwErr = GetLastError();
1421 CloseHandle(m_obj->map_handle);
1422 m_obj->map_handle = NULL;
1423 }
1424 } else
1425 dwErr = GetLastError();
1426 Py_DECREF(m_obj);
1427 PyErr_SetFromWindowsErr(dwErr);
1428 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001429}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001430#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001431
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001432static void
1433setint(PyObject *d, const char *name, long value)
1434{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001435 PyObject *o = PyLong_FromLong(value);
1436 if (o && PyDict_SetItemString(d, name, o) == 0) {
1437 Py_DECREF(o);
1438 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001439}
1440
Martin v. Löwis1a214512008-06-11 05:26:20 +00001441
1442static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001443 PyModuleDef_HEAD_INIT,
1444 "mmap",
1445 NULL,
1446 -1,
1447 NULL,
1448 NULL,
1449 NULL,
1450 NULL,
1451 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001452};
1453
Mark Hammond62b1ab12002-07-23 06:31:15 +00001454PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001455PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001456{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001457 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001458
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001459 if (PyType_Ready(&mmap_object_type) < 0)
1460 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001461
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001462 module = PyModule_Create(&mmapmodule);
1463 if (module == NULL)
1464 return NULL;
1465 dict = PyModule_GetDict(module);
1466 if (!dict)
1467 return NULL;
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001468 PyDict_SetItemString(dict, "error", PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001469 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001470#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001471 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001472#endif
1473#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001474 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001475#endif
1476#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001477 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001478#endif
1479
1480#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001481 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001482#endif
1483#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001484 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001485#endif
1486#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001487 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001488#endif
1489#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001490 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001491#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001492#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001493 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1494 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001495#endif
1496
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001497 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001498
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001499 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001500
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001501 setint(dict, "ACCESS_READ", ACCESS_READ);
1502 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1503 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1504 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001505}