blob: e01de441bd6609f357f38c46eea9c87f7a38c2b8 [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 Peterson37768362016-10-05 23:29:07 -0700386 if (!is_writable(self)) {
387 PyBuffer_Release(&data);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700388 return NULL;
Benjamin Peterson37768362016-10-05 23:29:07 -0700389 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700390
391 if (self->pos > self->size || self->size - self->pos < data.len) {
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200392 PyBuffer_Release(&data);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700393 PyErr_SetString(PyExc_ValueError, "data out of range");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000394 return NULL;
395 }
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200396
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700397 memcpy(&self->data[self->pos], data.buf, data.len);
398 self->pos += data.len;
Serhiy Storchaka8490f5a2015-03-20 09:00:36 +0200399 PyBuffer_Release(&data);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000400 Py_INCREF(Py_None);
401 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000402}
403
404static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000405mmap_write_byte_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000406 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000407{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000408 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000409
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000410 CHECK_VALID(NULL);
411 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
412 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000413
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000414 if (!is_writable(self))
415 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000416
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000417 if (self->pos < self->size) {
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700418 self->data[self->pos++] = value;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000419 Py_INCREF(Py_None);
420 return Py_None;
421 }
422 else {
423 PyErr_SetString(PyExc_ValueError, "write byte out of range");
424 return NULL;
425 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000426}
Tim Petersec0a5f02006-02-16 23:47:20 +0000427
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000428static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000429mmap_size_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000430 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000431{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000432 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000433
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000434#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000435 if (self->file_handle != INVALID_HANDLE_VALUE) {
436 DWORD low,high;
437 PY_LONG_LONG size;
438 low = GetFileSize(self->file_handle, &high);
439 if (low == INVALID_FILE_SIZE) {
440 /* It might be that the function appears to have failed,
441 when indeed its size equals INVALID_FILE_SIZE */
442 DWORD error = GetLastError();
443 if (error != NO_ERROR)
444 return PyErr_SetFromWindowsErr(error);
445 }
446 if (!high && low < LONG_MAX)
447 return PyLong_FromLong((long)low);
448 size = (((PY_LONG_LONG)high)<<32) + low;
449 return PyLong_FromLongLong(size);
450 } else {
451 return PyLong_FromSsize_t(self->size);
452 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000453#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000454
455#ifdef UNIX
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000456 {
Victor Stinnere134a7f2015-03-30 10:09:31 +0200457 struct _Py_stat_struct status;
458 if (_Py_fstat(self->fd, &status) == -1)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000459 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000460#ifdef HAVE_LARGEFILE_SUPPORT
Victor Stinnere134a7f2015-03-30 10:09:31 +0200461 return PyLong_FromLongLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000462#else
Victor Stinnere134a7f2015-03-30 10:09:31 +0200463 return PyLong_FromLong(status.st_size);
Antoine Pitrou97696cb2011-02-21 23:46:27 +0000464#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000465 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000466#endif /* UNIX */
467}
468
469/* This assumes that you want the entire file mapped,
470 / and when recreating the map will make the new file
471 / have the new size
472 /
473 / Is this really necessary? This could easily be done
474 / from python by just closing and re-opening with the
475 / new size?
476 */
477
478static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000479mmap_resize_method(mmap_object *self,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000480 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000481{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000482 Py_ssize_t new_size;
483 CHECK_VALID(NULL);
484 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
485 !is_resizeable(self)) {
486 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700487 }
488 if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) {
489 PyErr_SetString(PyExc_ValueError, "new size out of range");
490 return NULL;
491 }
492
493 {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000494#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000495 DWORD dwErrCode = 0;
496 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
497 /* First, unmap the file view */
498 UnmapViewOfFile(self->data);
499 self->data = NULL;
500 /* Close the mapping object */
501 CloseHandle(self->map_handle);
502 self->map_handle = NULL;
503 /* Move to the desired EOF position */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000504 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
505 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
506 off_hi = (DWORD)(self->offset >> 32);
507 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000508 SetFilePointer(self->file_handle,
509 newSizeLow, &newSizeHigh, FILE_BEGIN);
510 /* Change the size of the file */
511 SetEndOfFile(self->file_handle);
512 /* Create another mapping object and remap the file view */
513 self->map_handle = CreateFileMapping(
514 self->file_handle,
515 NULL,
516 PAGE_READWRITE,
517 0,
518 0,
519 self->tagname);
520 if (self->map_handle != NULL) {
521 self->data = (char *) MapViewOfFile(self->map_handle,
522 FILE_MAP_WRITE,
523 off_hi,
524 off_lo,
525 new_size);
526 if (self->data != NULL) {
527 self->size = new_size;
528 Py_INCREF(Py_None);
529 return Py_None;
530 } else {
531 dwErrCode = GetLastError();
532 CloseHandle(self->map_handle);
533 self->map_handle = NULL;
534 }
535 } else {
536 dwErrCode = GetLastError();
537 }
538 PyErr_SetFromWindowsErr(dwErrCode);
539 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000540#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000541
542#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000543#ifndef HAVE_MREMAP
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000544 PyErr_SetString(PyExc_SystemError,
545 "mmap: resizing not available--no mremap()");
546 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000547#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000548 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000549
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700550 if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200551 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000552 return NULL;
553 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000554
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000555#ifdef MREMAP_MAYMOVE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000556 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000557#else
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700558#if defined(__NetBSD__)
559 newmap = mremap(self->data, self->size, self->data, new_size, 0);
560#else
561 newmap = mremap(self->data, self->size, new_size, 0);
562#endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000563#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000564 if (newmap == (void *)-1)
565 {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200566 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000567 return NULL;
568 }
569 self->data = newmap;
570 self->size = new_size;
571 Py_INCREF(Py_None);
572 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000573#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000574#endif /* UNIX */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000575 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000576}
577
578static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000579mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000580{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000581 CHECK_VALID(NULL);
582 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000583}
584
585static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000586mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000587{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000588 Py_ssize_t offset = 0;
589 Py_ssize_t size = self->size;
590 CHECK_VALID(NULL);
591 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
592 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700593 if (size < 0 || offset < 0 || self->size - offset < size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000594 PyErr_SetString(PyExc_ValueError, "flush values out of range");
595 return NULL;
596 }
R. David Murraye194dd62010-10-18 01:14:06 +0000597
598 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
599 return PyLong_FromLong(0);
600
Christian Heimesaf98da12008-01-27 15:18:18 +0000601#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000602 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000603#elif defined(UNIX)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000604 /* XXX semantics of return value? */
605 /* XXX flags for msync? */
606 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200607 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000608 return NULL;
609 }
610 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000611#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000612 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
613 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000614#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000615}
616
617static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000618mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000619{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000620 Py_ssize_t dist;
621 int how=0;
622 CHECK_VALID(NULL);
623 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
624 return NULL;
625 else {
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700626 Py_ssize_t where;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000627 switch (how) {
628 case 0: /* relative to start */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000629 where = dist;
630 break;
631 case 1: /* relative to current position */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700632 if (PY_SSIZE_T_MAX - self->pos < dist)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000633 goto onoutofrange;
634 where = self->pos + dist;
635 break;
636 case 2: /* relative to end */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700637 if (PY_SSIZE_T_MAX - self->size < dist)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000638 goto onoutofrange;
639 where = self->size + dist;
640 break;
641 default:
642 PyErr_SetString(PyExc_ValueError, "unknown seek type");
643 return NULL;
644 }
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700645 if (where > self->size || where < 0)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000646 goto onoutofrange;
647 self->pos = where;
648 Py_INCREF(Py_None);
649 return Py_None;
650 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000651
Tim Peters5ebfd362001-11-13 23:11:19 +0000652 onoutofrange:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000653 PyErr_SetString(PyExc_ValueError, "seek out of range");
654 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000655}
656
657static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000658mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000659{
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700660 Py_ssize_t dest, src, cnt;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000661 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700662 if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) ||
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000663 !is_writable(self)) {
664 return NULL;
665 } else {
666 /* bounds check the values */
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700667 if (dest < 0 || src < 0 || cnt < 0)
668 goto bounds;
669 if (self->size - dest < cnt || self->size - src < cnt)
670 goto bounds;
671
672 memmove(&self->data[dest], &self->data[src], cnt);
673
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000674 Py_INCREF(Py_None);
675 return Py_None;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700676
677 bounds:
678 PyErr_SetString(PyExc_ValueError,
679 "source, destination, or count out of range");
680 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000681 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000682}
683
Georg Brandl0bccc182010-08-01 14:50:00 +0000684static PyObject *
685mmap_closed_get(mmap_object *self)
686{
687#ifdef MS_WINDOWS
688 return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
689#elif defined(UNIX)
690 return PyBool_FromLong(self->data == NULL ? 1 : 0);
691#endif
692}
693
694static PyObject *
695mmap__enter__method(mmap_object *self, PyObject *args)
696{
697 CHECK_VALID(NULL);
698
699 Py_INCREF(self);
700 return (PyObject *)self;
701}
702
703static PyObject *
704mmap__exit__method(PyObject *self, PyObject *args)
705{
Martin v. Löwisbd928fe2011-10-14 10:20:37 +0200706 _Py_IDENTIFIER(close);
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200707
708 return _PyObject_CallMethodId(self, &PyId_close, NULL);
Georg Brandl0bccc182010-08-01 14:50:00 +0000709}
710
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300711#ifdef MS_WINDOWS
712static PyObject *
713mmap__sizeof__method(mmap_object *self, void *unused)
714{
715 Py_ssize_t res;
716
Serhiy Storchaka5c4064e2015-12-19 20:05:25 +0200717 res = _PyObject_SIZE(Py_TYPE(self));
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300718 if (self->tagname)
719 res += strlen(self->tagname) + 1;
720 return PyLong_FromSsize_t(res);
721}
722#endif
723
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000724static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000725 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
726 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
727 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
728 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
729 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
730 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
731 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
732 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
733 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
734 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
735 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
736 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
737 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
738 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Georg Brandl0bccc182010-08-01 14:50:00 +0000739 {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS},
740 {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS},
Serhiy Storchaka76b47652014-08-19 17:11:20 +0300741#ifdef MS_WINDOWS
742 {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS},
743#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000744 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000745};
746
Georg Brandl0bccc182010-08-01 14:50:00 +0000747static PyGetSetDef mmap_object_getset[] = {
748 {"closed", (getter) mmap_closed_get, NULL, NULL},
749 {NULL}
750};
751
752
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000753/* Functions for treating an mmap'ed file as a buffer */
754
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000755static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000756mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000757{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000758 CHECK_VALID(-1);
759 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
760 (self->access == ACCESS_READ), flags) < 0)
761 return -1;
762 self->exports++;
763 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000764}
765
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000766static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000767mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000768{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000769 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000770}
771
Martin v. Löwis18e16552006-02-15 17:27:45 +0000772static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000773mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000774{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000775 CHECK_VALID(-1);
776 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000777}
778
779static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000780mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000781{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000782 CHECK_VALID(NULL);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700783 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000784 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
785 return NULL;
786 }
787 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000788}
789
790static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000791mmap_subscript(mmap_object *self, PyObject *item)
792{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000793 CHECK_VALID(NULL);
794 if (PyIndex_Check(item)) {
795 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
796 if (i == -1 && PyErr_Occurred())
797 return NULL;
798 if (i < 0)
799 i += self->size;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700800 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000801 PyErr_SetString(PyExc_IndexError,
802 "mmap index out of range");
803 return NULL;
804 }
805 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
806 }
807 else if (PySlice_Check(item)) {
808 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000809
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000810 if (PySlice_GetIndicesEx(item, self->size,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000811 &start, &stop, &step, &slicelen) < 0) {
812 return NULL;
813 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000814
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000815 if (slicelen <= 0)
816 return PyBytes_FromStringAndSize("", 0);
817 else if (step == 1)
818 return PyBytes_FromStringAndSize(self->data + start,
819 slicelen);
820 else {
821 char *result_buf = (char *)PyMem_Malloc(slicelen);
822 Py_ssize_t cur, i;
823 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000824
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000825 if (result_buf == NULL)
826 return PyErr_NoMemory();
827 for (cur = start, i = 0; i < slicelen;
828 cur += step, i++) {
829 result_buf[i] = self->data[cur];
830 }
831 result = PyBytes_FromStringAndSize(result_buf,
832 slicelen);
833 PyMem_Free(result_buf);
834 return result;
835 }
836 }
837 else {
838 PyErr_SetString(PyExc_TypeError,
839 "mmap indices must be integers");
840 return NULL;
841 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000842}
843
844static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000845mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000846{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000847 CHECK_VALID(NULL);
848 PyErr_SetString(PyExc_SystemError,
849 "mmaps don't support concatenation");
850 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000851}
852
853static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000854mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000855{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000856 CHECK_VALID(NULL);
857 PyErr_SetString(PyExc_SystemError,
858 "mmaps don't support repeat operation");
859 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000860}
861
862static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000863mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000864{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000865 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000866
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000867 CHECK_VALID(-1);
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700868 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000869 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
870 return -1;
871 }
872 if (v == NULL) {
873 PyErr_SetString(PyExc_TypeError,
874 "mmap object doesn't support item deletion");
875 return -1;
876 }
877 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
878 PyErr_SetString(PyExc_IndexError,
879 "mmap assignment must be length-1 bytes()");
880 return -1;
881 }
882 if (!is_writable(self))
883 return -1;
884 buf = PyBytes_AsString(v);
885 self->data[i] = buf[0];
886 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000887}
888
Thomas Woutersed03b412007-08-28 21:37:11 +0000889static int
890mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
891{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000892 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000893
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000894 if (!is_writable(self))
895 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000896
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000897 if (PyIndex_Check(item)) {
898 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
899 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000900
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000901 if (i == -1 && PyErr_Occurred())
902 return -1;
903 if (i < 0)
904 i += self->size;
Benjamin Petersoncd04db02016-10-05 21:45:48 -0700905 if (i < 0 || i >= self->size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000906 PyErr_SetString(PyExc_IndexError,
907 "mmap index out of range");
908 return -1;
909 }
910 if (value == NULL) {
911 PyErr_SetString(PyExc_TypeError,
912 "mmap doesn't support item deletion");
913 return -1;
914 }
915 if (!PyIndex_Check(value)) {
916 PyErr_SetString(PyExc_TypeError,
917 "mmap item value must be an int");
918 return -1;
919 }
920 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
921 if (v == -1 && PyErr_Occurred())
922 return -1;
923 if (v < 0 || v > 255) {
924 PyErr_SetString(PyExc_ValueError,
925 "mmap item value must be "
926 "in range(0, 256)");
927 return -1;
928 }
Antoine Pitrou22e41552010-08-15 18:07:50 +0000929 self->data[i] = (char) v;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000930 return 0;
931 }
932 else if (PySlice_Check(item)) {
933 Py_ssize_t start, stop, step, slicelen;
934 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000935
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000936 if (PySlice_GetIndicesEx(item,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000937 self->size, &start, &stop,
938 &step, &slicelen) < 0) {
939 return -1;
940 }
941 if (value == NULL) {
942 PyErr_SetString(PyExc_TypeError,
943 "mmap object doesn't support slice deletion");
944 return -1;
945 }
946 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
947 return -1;
948 if (vbuf.len != slicelen) {
949 PyErr_SetString(PyExc_IndexError,
950 "mmap slice assignment is wrong size");
951 PyBuffer_Release(&vbuf);
952 return -1;
953 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000954
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000955 if (slicelen == 0) {
956 }
957 else if (step == 1) {
958 memcpy(self->data + start, vbuf.buf, slicelen);
959 }
960 else {
961 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000962
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000963 for (cur = start, i = 0;
964 i < slicelen;
965 cur += step, i++)
966 {
967 self->data[cur] = ((char *)vbuf.buf)[i];
968 }
969 }
970 PyBuffer_Release(&vbuf);
971 return 0;
972 }
973 else {
974 PyErr_SetString(PyExc_TypeError,
975 "mmap indices must be integer");
976 return -1;
977 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000978}
979
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000980static PySequenceMethods mmap_as_sequence = {
Stefan Krah23186992012-03-06 15:37:36 +0100981 (lenfunc)mmap_length, /*sq_length*/
982 (binaryfunc)mmap_concat, /*sq_concat*/
983 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
984 (ssizeargfunc)mmap_item, /*sq_item*/
985 0, /*sq_slice*/
986 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
987 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000988};
989
Thomas Woutersed03b412007-08-28 21:37:11 +0000990static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000991 (lenfunc)mmap_length,
992 (binaryfunc)mmap_subscript,
993 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000994};
995
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000996static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000997 (getbufferproc)mmap_buffer_getbuf,
998 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000999};
1000
Georg Brandl86def6c2008-01-21 20:36:10 +00001001static PyObject *
1002new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1003
Christian Heimese1c98112008-01-21 11:20:28 +00001004PyDoc_STRVAR(mmap_doc,
1005"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1006\n\
1007Maps length bytes from the file specified by the file handle fileno,\n\
1008and returns a mmap object. If length is larger than the current size\n\
1009of the file, the file is extended to contain length bytes. If length\n\
1010is 0, the maximum length of the map is the current size of the file,\n\
1011except that if the file is empty Windows raises an exception (you cannot\n\
1012create an empty mapping on Windows).\n\
1013\n\
1014Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1015\n\
1016Maps length bytes from the file specified by the file descriptor fileno,\n\
1017and returns a mmap object. If length is 0, the maximum length of the map\n\
1018will be the current size of the file when mmap is called.\n\
1019flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1020private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +00001021object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +00001022that's shared with all other processes mapping the same areas of the file.\n\
1023The default value is MAP_SHARED.\n\
1024\n\
1025To map anonymous memory, pass -1 as the fileno (both versions).");
1026
1027
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001028static PyTypeObject mmap_object_type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001029 PyVarObject_HEAD_INIT(NULL, 0)
1030 "mmap.mmap", /* tp_name */
1031 sizeof(mmap_object), /* tp_size */
1032 0, /* tp_itemsize */
1033 /* methods */
1034 (destructor) mmap_object_dealloc, /* tp_dealloc */
1035 0, /* tp_print */
1036 0, /* tp_getattr */
1037 0, /* tp_setattr */
1038 0, /* tp_reserved */
1039 0, /* tp_repr */
1040 0, /* tp_as_number */
1041 &mmap_as_sequence, /*tp_as_sequence*/
1042 &mmap_as_mapping, /*tp_as_mapping*/
1043 0, /*tp_hash*/
1044 0, /*tp_call*/
1045 0, /*tp_str*/
1046 PyObject_GenericGetAttr, /*tp_getattro*/
1047 0, /*tp_setattro*/
1048 &mmap_as_buffer, /*tp_as_buffer*/
Stefan Krah23186992012-03-06 15:37:36 +01001049 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001050 mmap_doc, /*tp_doc*/
1051 0, /* tp_traverse */
1052 0, /* tp_clear */
1053 0, /* tp_richcompare */
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001054 offsetof(mmap_object, weakreflist), /* tp_weaklistoffset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001055 0, /* tp_iter */
1056 0, /* tp_iternext */
1057 mmap_object_methods, /* tp_methods */
1058 0, /* tp_members */
Georg Brandl0bccc182010-08-01 14:50:00 +00001059 mmap_object_getset, /* tp_getset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001060 0, /* tp_base */
1061 0, /* tp_dict */
1062 0, /* tp_descr_get */
1063 0, /* tp_descr_set */
1064 0, /* tp_dictoffset */
Stefan Krah23186992012-03-06 15:37:36 +01001065 0, /* tp_init */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001066 PyType_GenericAlloc, /* tp_alloc */
1067 new_mmap_object, /* tp_new */
Stefan Krah23186992012-03-06 15:37:36 +01001068 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001069};
1070
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001071
Tim Petersec0a5f02006-02-16 23:47:20 +00001072#ifdef UNIX
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001073#ifdef HAVE_LARGEFILE_SUPPORT
1074#define _Py_PARSE_OFF_T "L"
1075#else
1076#define _Py_PARSE_OFF_T "l"
1077#endif
1078
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001079static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001080new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001081{
Victor Stinnere134a7f2015-03-30 10:09:31 +02001082 struct _Py_stat_struct status;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001083 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001084 Py_ssize_t map_size;
1085 off_t offset = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001086 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1087 int devzero = -1;
1088 int access = (int)ACCESS_DEFAULT;
1089 static char *keywords[] = {"fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001090 "flags", "prot",
1091 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001092
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001093 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords,
1094 &fd, &map_size, &flags, &prot,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001095 &access, &offset))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001096 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001097 if (map_size < 0) {
1098 PyErr_SetString(PyExc_OverflowError,
1099 "memory mapped length must be postiive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001100 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001101 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001102 if (offset < 0) {
1103 PyErr_SetString(PyExc_OverflowError,
1104 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001105 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001106 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001107
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001108 if ((access != (int)ACCESS_DEFAULT) &&
1109 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1110 return PyErr_Format(PyExc_ValueError,
1111 "mmap can't specify both access and flags, prot.");
1112 switch ((access_mode)access) {
1113 case ACCESS_READ:
1114 flags = MAP_SHARED;
1115 prot = PROT_READ;
1116 break;
1117 case ACCESS_WRITE:
1118 flags = MAP_SHARED;
1119 prot = PROT_READ | PROT_WRITE;
1120 break;
1121 case ACCESS_COPY:
1122 flags = MAP_PRIVATE;
1123 prot = PROT_READ | PROT_WRITE;
1124 break;
1125 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001126 /* map prot to access type */
1127 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1128 /* ACCESS_DEFAULT */
1129 }
1130 else if (prot & PROT_WRITE) {
1131 access = ACCESS_WRITE;
1132 }
1133 else {
1134 access = ACCESS_READ;
1135 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001136 break;
1137 default:
1138 return PyErr_Format(PyExc_ValueError,
1139 "mmap invalid access parameter.");
1140 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001141
Victor Stinnera6cd0cf2011-05-02 01:05:37 +02001142#ifdef __APPLE__
1143 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1144 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1145 if (fd != -1)
1146 (void)fcntl(fd, F_FULLFSYNC);
1147#endif
Victor Stinnere134a7f2015-03-30 10:09:31 +02001148 if (fd != -1 && _Py_fstat_noraise(fd, &status) == 0
1149 && S_ISREG(status.st_mode)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001150 if (map_size == 0) {
Victor Stinnere134a7f2015-03-30 10:09:31 +02001151 if (status.st_size == 0) {
Jesus Cea941bfcc2012-09-10 00:27:55 +02001152 PyErr_SetString(PyExc_ValueError,
1153 "cannot mmap an empty file");
1154 return NULL;
1155 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001156 if (offset >= status.st_size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001157 PyErr_SetString(PyExc_ValueError,
1158 "mmap offset is greater than file size");
1159 return NULL;
1160 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001161 if (status.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001162 PyErr_SetString(PyExc_ValueError,
1163 "mmap length is too large");
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001164 return NULL;
1165 }
Victor Stinnere134a7f2015-03-30 10:09:31 +02001166 map_size = (Py_ssize_t) (status.st_size - offset);
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001167 } else if (offset > status.st_size || status.st_size - offset < map_size) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001168 PyErr_SetString(PyExc_ValueError,
1169 "mmap length is greater than file size");
1170 return NULL;
1171 }
1172 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001173 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1174 if (m_obj == NULL) {return NULL;}
1175 m_obj->data = NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001176 m_obj->size = map_size;
1177 m_obj->pos = 0;
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001178 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001179 m_obj->exports = 0;
1180 m_obj->offset = offset;
1181 if (fd == -1) {
1182 m_obj->fd = -1;
1183 /* Assume the caller wants to map anonymous memory.
1184 This is the same behaviour as Windows. mmap.mmap(-1, size)
1185 on both Windows and Unix map anonymous memory.
1186 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001187#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001188 /* BSD way to map anonymous memory */
1189 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001190#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001191 /* SVR4 method to map anonymous memory is to open /dev/zero */
Victor Stinnerdaf45552013-08-28 00:53:59 +02001192 fd = devzero = _Py_open("/dev/zero", O_RDWR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001193 if (devzero == -1) {
1194 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001195 return NULL;
1196 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001197#endif
Victor Stinnerdaf45552013-08-28 00:53:59 +02001198 }
1199 else {
1200 m_obj->fd = _Py_dup(fd);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001201 if (m_obj->fd == -1) {
1202 Py_DECREF(m_obj);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001203 return NULL;
1204 }
1205 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001206
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001207 m_obj->data = mmap(NULL, map_size,
1208 prot, flags,
1209 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001210
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001211 if (devzero != -1) {
1212 close(devzero);
1213 }
1214
1215 if (m_obj->data == (char *)-1) {
1216 m_obj->data = NULL;
1217 Py_DECREF(m_obj);
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001218 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001219 return NULL;
1220 }
1221 m_obj->access = (access_mode)access;
1222 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001223}
1224#endif /* UNIX */
1225
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001226#ifdef MS_WINDOWS
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001227
1228/* A note on sizes and offsets: while the actual map size must hold in a
1229 Py_ssize_t, both the total file size and the start offset can be longer
1230 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1231*/
1232
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001233static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001234new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001235{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001236 mmap_object *m_obj;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001237 Py_ssize_t map_size;
1238 PY_LONG_LONG offset = 0, size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001239 DWORD off_hi; /* upper 32 bits of offset */
1240 DWORD off_lo; /* lower 32 bits of offset */
1241 DWORD size_hi; /* upper 32 bits of size */
1242 DWORD size_lo; /* lower 32 bits of size */
1243 char *tagname = "";
1244 DWORD dwErr = 0;
1245 int fileno;
1246 HANDLE fh = 0;
1247 int access = (access_mode)ACCESS_DEFAULT;
1248 DWORD flProtect, dwDesiredAccess;
1249 static char *keywords[] = { "fileno", "length",
Stefan Krah23186992012-03-06 15:37:36 +01001250 "tagname",
1251 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001252
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001253 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords,
1254 &fileno, &map_size,
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001255 &tagname, &access, &offset)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001256 return NULL;
1257 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001258
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001259 switch((access_mode)access) {
1260 case ACCESS_READ:
1261 flProtect = PAGE_READONLY;
1262 dwDesiredAccess = FILE_MAP_READ;
1263 break;
1264 case ACCESS_DEFAULT: case ACCESS_WRITE:
1265 flProtect = PAGE_READWRITE;
1266 dwDesiredAccess = FILE_MAP_WRITE;
1267 break;
1268 case ACCESS_COPY:
1269 flProtect = PAGE_WRITECOPY;
1270 dwDesiredAccess = FILE_MAP_COPY;
1271 break;
1272 default:
1273 return PyErr_Format(PyExc_ValueError,
1274 "mmap invalid access parameter.");
1275 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001276
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001277 if (map_size < 0) {
1278 PyErr_SetString(PyExc_OverflowError,
1279 "memory mapped length must be postiive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001280 return NULL;
Benjamin Petersoncd04db02016-10-05 21:45:48 -07001281 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001282 if (offset < 0) {
1283 PyErr_SetString(PyExc_OverflowError,
1284 "memory mapped offset must be positive");
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001285 return NULL;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001286 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001287
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001288 /* assume -1 and 0 both mean invalid filedescriptor
1289 to 'anonymously' map memory.
1290 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1291 XXX: Should this code be added?
1292 if (fileno == 0)
1293 PyErr_WarnEx(PyExc_DeprecationWarning,
1294 "don't use 0 for anonymous memory",
1295 1);
1296 */
1297 if (fileno != -1 && fileno != 0) {
Brian Curtinea47eaa2010-08-01 15:26:26 +00001298 /* Ensure that fileno is within the CRT's valid range */
Steve Dower8fc89802015-04-12 00:26:27 -04001299 if (!_PyVerify_fd(fileno)) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001300 PyErr_SetFromErrno(PyExc_OSError);
Brian Curtinea47eaa2010-08-01 15:26:26 +00001301 return NULL;
1302 }
Steve Dower8fc89802015-04-12 00:26:27 -04001303 _Py_BEGIN_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001304 fh = (HANDLE)_get_osfhandle(fileno);
Steve Dower8fc89802015-04-12 00:26:27 -04001305 _Py_END_SUPPRESS_IPH
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001306 if (fh==(HANDLE)-1) {
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001307 PyErr_SetFromErrno(PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001308 return NULL;
1309 }
1310 /* Win9x appears to need us seeked to zero */
1311 lseek(fileno, 0, SEEK_SET);
1312 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001313
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001314 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1315 if (m_obj == NULL)
1316 return NULL;
1317 /* Set every field to an invalid marker, so we can safely
1318 destruct the object in the face of failure */
1319 m_obj->data = NULL;
1320 m_obj->file_handle = INVALID_HANDLE_VALUE;
1321 m_obj->map_handle = NULL;
1322 m_obj->tagname = NULL;
1323 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001324
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001325 if (fh) {
1326 /* It is necessary to duplicate the handle, so the
1327 Python code can close it on us */
1328 if (!DuplicateHandle(
1329 GetCurrentProcess(), /* source process handle */
1330 fh, /* handle to be duplicated */
1331 GetCurrentProcess(), /* target proc handle */
1332 (LPHANDLE)&m_obj->file_handle, /* result */
1333 0, /* access - ignored due to options value */
1334 FALSE, /* inherited by child processes? */
1335 DUPLICATE_SAME_ACCESS)) { /* options */
1336 dwErr = GetLastError();
1337 Py_DECREF(m_obj);
1338 PyErr_SetFromWindowsErr(dwErr);
1339 return NULL;
1340 }
1341 if (!map_size) {
1342 DWORD low,high;
1343 low = GetFileSize(fh, &high);
1344 /* low might just happen to have the value INVALID_FILE_SIZE;
1345 so we need to check the last error also. */
1346 if (low == INVALID_FILE_SIZE &&
1347 (dwErr = GetLastError()) != NO_ERROR) {
1348 Py_DECREF(m_obj);
1349 return PyErr_SetFromWindowsErr(dwErr);
1350 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001351
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001352 size = (((PY_LONG_LONG) high) << 32) + low;
Jesus Cea1f2799b2012-09-10 22:49:50 +02001353 if (size == 0) {
1354 PyErr_SetString(PyExc_ValueError,
1355 "cannot mmap an empty file");
Jesus Ceae8db3562012-09-10 22:58:07 +02001356 Py_DECREF(m_obj);
Jesus Cea1f2799b2012-09-10 22:49:50 +02001357 return NULL;
1358 }
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001359 if (offset >= size) {
Antoine Pitrou305bc9e2011-01-20 21:07:24 +00001360 PyErr_SetString(PyExc_ValueError,
1361 "mmap offset is greater than file size");
1362 Py_DECREF(m_obj);
1363 return NULL;
1364 }
Richard Oudkerk0d09ba82013-02-13 12:18:03 +00001365 if (size - offset > PY_SSIZE_T_MAX) {
1366 PyErr_SetString(PyExc_ValueError,
1367 "mmap length is too large");
1368 Py_DECREF(m_obj);
1369 return NULL;
1370 }
1371 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001372 } else {
1373 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001374 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001375 }
1376 }
1377 else {
1378 m_obj->size = map_size;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001379 size = offset + map_size;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001380 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001381
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001382 /* set the initial position */
1383 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001384
Antoine Pitrouc53204b2013-08-05 23:17:30 +02001385 m_obj->weakreflist = NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001386 m_obj->exports = 0;
1387 /* set the tag name */
1388 if (tagname != NULL && *tagname != '\0') {
1389 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1390 if (m_obj->tagname == NULL) {
1391 PyErr_NoMemory();
1392 Py_DECREF(m_obj);
1393 return NULL;
1394 }
1395 strcpy(m_obj->tagname, tagname);
1396 }
1397 else
1398 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001399
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001400 m_obj->access = (access_mode)access;
Antoine Pitrou97696cb2011-02-21 23:46:27 +00001401 size_hi = (DWORD)(size >> 32);
1402 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001403 off_hi = (DWORD)(offset >> 32);
1404 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001405 /* For files, it would be sufficient to pass 0 as size.
1406 For anonymous maps, we have to pass the size explicitly. */
1407 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1408 NULL,
1409 flProtect,
1410 size_hi,
1411 size_lo,
1412 m_obj->tagname);
1413 if (m_obj->map_handle != NULL) {
1414 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1415 dwDesiredAccess,
1416 off_hi,
1417 off_lo,
1418 m_obj->size);
1419 if (m_obj->data != NULL)
1420 return (PyObject *)m_obj;
1421 else {
1422 dwErr = GetLastError();
1423 CloseHandle(m_obj->map_handle);
1424 m_obj->map_handle = NULL;
1425 }
1426 } else
1427 dwErr = GetLastError();
1428 Py_DECREF(m_obj);
1429 PyErr_SetFromWindowsErr(dwErr);
1430 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001431}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001432#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001433
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001434static void
1435setint(PyObject *d, const char *name, long value)
1436{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001437 PyObject *o = PyLong_FromLong(value);
1438 if (o && PyDict_SetItemString(d, name, o) == 0) {
1439 Py_DECREF(o);
1440 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001441}
1442
Martin v. Löwis1a214512008-06-11 05:26:20 +00001443
1444static struct PyModuleDef mmapmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001445 PyModuleDef_HEAD_INIT,
1446 "mmap",
1447 NULL,
1448 -1,
1449 NULL,
1450 NULL,
1451 NULL,
1452 NULL,
1453 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001454};
1455
Mark Hammond62b1ab12002-07-23 06:31:15 +00001456PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001457PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001458{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001459 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001460
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001461 if (PyType_Ready(&mmap_object_type) < 0)
1462 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001463
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001464 module = PyModule_Create(&mmapmodule);
1465 if (module == NULL)
1466 return NULL;
1467 dict = PyModule_GetDict(module);
1468 if (!dict)
1469 return NULL;
Antoine Pitrou6b4883d2011-10-12 02:54:14 +02001470 PyDict_SetItemString(dict, "error", PyExc_OSError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001471 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001472#ifdef PROT_EXEC
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001473 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001474#endif
1475#ifdef PROT_READ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001476 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001477#endif
1478#ifdef PROT_WRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001479 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001480#endif
1481
1482#ifdef MAP_SHARED
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001483 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001484#endif
1485#ifdef MAP_PRIVATE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001486 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001487#endif
1488#ifdef MAP_DENYWRITE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001489 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001490#endif
1491#ifdef MAP_EXECUTABLE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001492 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001493#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001494#ifdef MAP_ANONYMOUS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001495 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1496 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001497#endif
1498
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001499 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001500
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001501 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001502
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001503 setint(dict, "ACCESS_READ", ACCESS_READ);
1504 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1505 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1506 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001507}