blob: c2ed5d13094eea7a0233987f3360c7edc349bf10 [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
6 / mmapmodule.cpp -- map a view of a file into memory
7 /
8 / todo: need permission flags, perhaps a 'chsize' analog
9 / not all functions check range yet!!!
10 /
11 /
Mark Hammond071864a2000-07-30 02:46:26 +000012 / This version of mmapmodule.c has been changed significantly
13 / from the original mmapfile.c on which it was based.
14 / The original version of mmapfile is maintained by Sam at
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000015 / ftp://squirl.nightmare.com/pub/python/python-ext.
16*/
17
Martin v. Löwiscfe7e092006-02-17 06:59:14 +000018#define PY_SSIZE_T_CLEAN
Guido van Rossum09fdf072000-03-31 01:17:07 +000019#include <Python.h>
20
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000021#ifndef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000022#define UNIX
23#endif
24
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000025#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000026#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000027static int
28my_getpagesize(void)
29{
Tim Peters5ebfd362001-11-13 23:11:19 +000030 SYSTEM_INFO si;
31 GetSystemInfo(&si);
32 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000033}
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000034#endif
35
36#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000037#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000038#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000039
Fred Drake145f96e2000-10-01 17:50:46 +000040#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
41static int
42my_getpagesize(void)
43{
Tim Peters5ebfd362001-11-13 23:11:19 +000044 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000045}
46#else
47#define my_getpagesize getpagesize
48#endif
49
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000050#endif /* UNIX */
51
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000052#include <string.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000053
54#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000055#include <sys/types.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000056#endif /* HAVE_SYS_TYPES_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000057
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000058/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000059#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
60# define MAP_ANONYMOUS MAP_ANON
61#endif
62
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000063static PyObject *mmap_module_error;
64
Tim Peters5ebfd362001-11-13 23:11:19 +000065typedef enum
66{
67 ACCESS_DEFAULT,
68 ACCESS_READ,
69 ACCESS_WRITE,
70 ACCESS_COPY
71} access_mode;
72
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000073typedef struct {
Guido van Rossum09fdf072000-03-31 01:17:07 +000074 PyObject_HEAD
75 char * data;
76 size_t size;
77 size_t pos;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000078 int exports;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000079
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000080#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +000081 HANDLE map_handle;
Mark Hammond071864a2000-07-30 02:46:26 +000082 HANDLE file_handle;
Guido van Rossum09fdf072000-03-31 01:17:07 +000083 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000084#endif
85
86#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000087 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000088#endif
Tim Peters5ebfd362001-11-13 23:11:19 +000089
90 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000091} mmap_object;
92
Tim Peters5ebfd362001-11-13 23:11:19 +000093
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000094static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +000095mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000096{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000097#ifdef MS_WINDOWS
Mark Hammond2cbed002000-07-30 02:22:43 +000098 if (m_obj->data != NULL)
99 UnmapViewOfFile (m_obj->data);
100 if (m_obj->map_handle != INVALID_HANDLE_VALUE)
101 CloseHandle (m_obj->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000102 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
103 CloseHandle (m_obj->file_handle);
Mark Hammond2cbed002000-07-30 02:22:43 +0000104 if (m_obj->tagname)
105 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000106#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000107
108#ifdef UNIX
Neal Norwitz6eac2002005-11-02 05:36:37 +0000109 if (m_obj->fd >= 0)
110 (void) close(m_obj->fd);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000111 if (m_obj->data!=NULL) {
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000112 msync(m_obj->data, m_obj->size, MS_SYNC);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000113 munmap(m_obj->data, m_obj->size);
114 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000115#endif /* UNIX */
116
Guido van Rossumb18618d2000-05-03 23:44:39 +0000117 PyObject_Del(m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000118}
119
120static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000121mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000122{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000123 if (self->exports > 0) {
124 PyErr_SetString(PyExc_BufferError, "cannot close "\
125 "exported pointers exist");
126 return NULL;
127 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000128#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000129 /* For each resource we maintain, we need to check
Tim Petersec0a5f02006-02-16 23:47:20 +0000130 the value is valid, and if so, free the resource
Mark Hammond071864a2000-07-30 02:46:26 +0000131 and set the member value to an invalid value so
132 the dealloc does not attempt to resource clearing
133 again.
134 TODO - should we check for errors in the close operations???
135 */
136 if (self->data != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000137 UnmapViewOfFile(self->data);
Mark Hammond071864a2000-07-30 02:46:26 +0000138 self->data = NULL;
139 }
140 if (self->map_handle != INVALID_HANDLE_VALUE) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000141 CloseHandle(self->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000142 self->map_handle = INVALID_HANDLE_VALUE;
143 }
144 if (self->file_handle != INVALID_HANDLE_VALUE) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000145 CloseHandle(self->file_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000146 self->file_handle = INVALID_HANDLE_VALUE;
147 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000148#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000149
150#ifdef UNIX
Neal Norwitz6eac2002005-11-02 05:36:37 +0000151 (void) close(self->fd);
152 self->fd = -1;
Neal Norwitze604c022003-01-10 20:52:16 +0000153 if (self->data != NULL) {
154 munmap(self->data, self->size);
155 self->data = NULL;
156 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000157#endif
158
Tim Peters8f9cc292006-02-17 00:00:20 +0000159 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000160 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000161}
162
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000163#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +0000164#define CHECK_VALID(err) \
165do { \
Guido van Rossum69c2b882003-04-09 19:31:02 +0000166 if (self->map_handle == INVALID_HANDLE_VALUE) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000167 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000168 return err; \
169 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000170} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000171#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000172
173#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000174#define CHECK_VALID(err) \
175do { \
176 if (self->data == NULL) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000177 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000178 return err; \
179 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000180} while (0)
181#endif /* UNIX */
182
183static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000184mmap_read_byte_method(mmap_object *self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000185 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000186{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000187 CHECK_VALID(NULL);
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000188 if (self->pos < self->size) {
Tim Petersd6283b82001-05-09 18:48:26 +0000189 char value = self->data[self->pos];
Guido van Rossum09fdf072000-03-31 01:17:07 +0000190 self->pos += 1;
Tim Petersd6283b82001-05-09 18:48:26 +0000191 return Py_BuildValue("c", value);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000192 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000193 PyErr_SetString(PyExc_ValueError, "read byte out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000194 return NULL;
195 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000196}
197
198static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000199mmap_read_line_method(mmap_object *self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000200 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000201{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000202 char *start = self->data+self->pos;
203 char *eof = self->data+self->size;
204 char *eol;
205 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000206
Guido van Rossum09fdf072000-03-31 01:17:07 +0000207 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000208
Fred Drake56a87a02000-04-04 18:17:35 +0000209 eol = memchr(start, '\n', self->size - self->pos);
210 if (!eol)
211 eol = eof;
212 else
213 ++eol; /* we're interested in the position after the
214 newline. */
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000215 result = PyBytes_FromStringAndSize(start, (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000216 self->pos += (eol - start);
Tim Peters23721ee2006-02-16 23:50:16 +0000217 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000218}
219
220static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000221mmap_read_method(mmap_object *self,
222 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000223{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000224 Py_ssize_t num_bytes;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000225 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000226
Guido van Rossum09fdf072000-03-31 01:17:07 +0000227 CHECK_VALID(NULL);
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000228 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000229 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000230
Guido van Rossum09fdf072000-03-31 01:17:07 +0000231 /* silently 'adjust' out-of-range requests */
232 if ((self->pos + num_bytes) > self->size) {
233 num_bytes -= (self->pos+num_bytes) - self->size;
234 }
Guido van Rossume5aeaad2007-07-26 18:28:23 +0000235 result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes);
Tim Petersec0a5f02006-02-16 23:47:20 +0000236 self->pos += num_bytes;
Tim Peters23721ee2006-02-16 23:50:16 +0000237 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000238}
239
240static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000241mmap_find_method(mmap_object *self,
242 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000243{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000244 Py_ssize_t start = self->pos;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000245 char *needle;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000246 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000247
Guido van Rossum09fdf072000-03-31 01:17:07 +0000248 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000249 if (!PyArg_ParseTuple(args, "s#|n:find", &needle, &len, &start)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000250 return NULL;
251 } else {
Greg Stein834f4dd2001-05-14 09:32:26 +0000252 char *p;
253 char *e = self->data + self->size;
254
255 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000256 start += self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000257 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000258 start = 0;
Tim Petersd401edd2001-05-14 23:19:12 +0000259 else if ((size_t)start > self->size)
Tim Peters5ebfd362001-11-13 23:11:19 +0000260 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000261
Tim Petersc9ffa062002-03-08 05:43:32 +0000262 for (p = self->data + start; p + len <= e; ++p) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000263 Py_ssize_t i;
Tim Petersc9ffa062002-03-08 05:43:32 +0000264 for (i = 0; i < len && needle[i] == p[i]; ++i)
265 /* nothing */;
266 if (i == len) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000267 return PyInt_FromSsize_t(p - self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000268 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000269 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000270 return PyInt_FromLong(-1);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000271 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000272}
273
Tim Petersec0a5f02006-02-16 23:47:20 +0000274static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000275is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000276{
277 if (self->access != ACCESS_READ)
Tim Petersec0a5f02006-02-16 23:47:20 +0000278 return 1;
Tim Peters5ebfd362001-11-13 23:11:19 +0000279 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
280 return 0;
281}
282
Tim Petersec0a5f02006-02-16 23:47:20 +0000283static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000284is_resizeable(mmap_object *self)
285{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000286 if (self->exports > 0) {
287 PyErr_SetString(PyExc_BufferError,
288 "mmap can't resize with extant buffers exported.");
289 return 0;
290 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000291 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000292 return 1;
Tim Petersec0a5f02006-02-16 23:47:20 +0000293 PyErr_Format(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000294 "mmap can't resize a readonly or copy-on-write memory map.");
295 return 0;
296}
297
298
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000299static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000300mmap_write_method(mmap_object *self,
301 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000302{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000303 Py_ssize_t length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000304 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000305
Guido van Rossum09fdf072000-03-31 01:17:07 +0000306 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000307 if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000308 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000309
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000310 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000311 return NULL;
312
Guido van Rossum09fdf072000-03-31 01:17:07 +0000313 if ((self->pos + length) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000314 PyErr_SetString(PyExc_ValueError, "data out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000315 return NULL;
316 }
Tim Peters8f9cc292006-02-17 00:00:20 +0000317 memcpy(self->data+self->pos, data, length);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000318 self->pos = self->pos+length;
Tim Peters8f9cc292006-02-17 00:00:20 +0000319 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000320 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000321}
322
323static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000324mmap_write_byte_method(mmap_object *self,
325 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000326{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000327 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000328
Guido van Rossum09fdf072000-03-31 01:17:07 +0000329 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000330 if (!PyArg_ParseTuple(args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000331 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000332
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000333 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000334 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000335 *(self->data+self->pos) = value;
336 self->pos += 1;
Tim Peters8f9cc292006-02-17 00:00:20 +0000337 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000338 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000339}
Tim Petersec0a5f02006-02-16 23:47:20 +0000340
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000341static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000342mmap_size_method(mmap_object *self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000343 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000344{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000345 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000346
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000347#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000348 if (self->file_handle != INVALID_HANDLE_VALUE) {
Martin v. Löwis15186072006-02-18 12:38:35 +0000349 DWORD low,high;
350 PY_LONG_LONG size;
351 low = GetFileSize(self->file_handle, &high);
352 if (low == INVALID_FILE_SIZE) {
353 /* It might be that the function appears to have failed,
354 when indeed its size equals INVALID_FILE_SIZE */
355 DWORD error = GetLastError();
356 if (error != NO_ERROR)
357 return PyErr_SetFromWindowsErr(error);
358 }
359 if (!high && low < LONG_MAX)
360 return PyInt_FromLong((long)low);
361 size = (((PY_LONG_LONG)high)<<32) + low;
362 return PyLong_FromLongLong(size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000363 } else {
Martin v. Löwis15186072006-02-18 12:38:35 +0000364 return PyInt_FromSsize_t(self->size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000365 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000366#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000367
368#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000369 {
370 struct stat buf;
371 if (-1 == fstat(self->fd, &buf)) {
372 PyErr_SetFromErrno(mmap_module_error);
373 return NULL;
374 }
Martin v. Löwis15186072006-02-18 12:38:35 +0000375 return PyInt_FromSsize_t(buf.st_size);
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000376 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000377#endif /* UNIX */
378}
379
380/* This assumes that you want the entire file mapped,
381 / and when recreating the map will make the new file
382 / have the new size
383 /
384 / Is this really necessary? This could easily be done
385 / from python by just closing and re-opening with the
386 / new size?
387 */
388
389static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000390mmap_resize_method(mmap_object *self,
391 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000392{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000393 Py_ssize_t new_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000394 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000395 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000396 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000397 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000398#ifdef MS_WINDOWS
Tim Petersec0a5f02006-02-16 23:47:20 +0000399 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000400 DWORD dwErrCode = 0;
Martin v. Löwis15186072006-02-18 12:38:35 +0000401 DWORD newSizeLow, newSizeHigh;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000402 /* First, unmap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000403 UnmapViewOfFile(self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000404 /* Close the mapping object */
Tim Peters8f9cc292006-02-17 00:00:20 +0000405 CloseHandle(self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000406 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000407#if SIZEOF_SIZE_T > 4
408 newSizeHigh = (DWORD)(new_size >> 32);
409 newSizeLow = (DWORD)(new_size & 0xFFFFFFFF);
410#else
411 newSizeHigh = 0;
Martin v. Löwis5bb8a152006-02-18 12:49:49 +0000412 newSizeLow = (DWORD)new_size;
Martin v. Löwis15186072006-02-18 12:38:35 +0000413#endif
Tim Peters8f9cc292006-02-17 00:00:20 +0000414 SetFilePointer(self->file_handle,
Martin v. Löwis15186072006-02-18 12:38:35 +0000415 newSizeLow, &newSizeHigh, FILE_BEGIN);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000416 /* Change the size of the file */
Tim Peters8f9cc292006-02-17 00:00:20 +0000417 SetEndOfFile(self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000418 /* Create another mapping object and remap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000419 self->map_handle = CreateFileMapping(
Mark Hammond071864a2000-07-30 02:46:26 +0000420 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000421 NULL,
422 PAGE_READWRITE,
Martin v. Löwis15186072006-02-18 12:38:35 +0000423 newSizeHigh,
424 newSizeLow,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000425 self->tagname);
426 if (self->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000427 self->data = (char *) MapViewOfFile(self->map_handle,
428 FILE_MAP_WRITE,
429 0,
430 0,
431 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000432 if (self->data != NULL) {
433 self->size = new_size;
Tim Peters8f9cc292006-02-17 00:00:20 +0000434 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000435 return Py_None;
436 } else {
437 dwErrCode = GetLastError();
438 }
439 } else {
440 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000441 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000442 PyErr_SetFromWindowsErr(dwErrCode);
Tim Peters23721ee2006-02-16 23:50:16 +0000443 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000444#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000445
446#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000447#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000448 } else {
449 PyErr_SetString(PyExc_SystemError,
450 "mmap: resizing not available--no mremap()");
451 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000452#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000453 } else {
Armin Rigo335ffe82005-09-20 19:04:02 +0000454 void *newmap;
455
Georg Brandl38387b82005-08-24 07:17:40 +0000456 if (ftruncate(self->fd, new_size) == -1) {
457 PyErr_SetFromErrno(mmap_module_error);
458 return NULL;
459 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000460
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000461#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000462 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000463#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000464 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000465#endif
Tim Petersec0a5f02006-02-16 23:47:20 +0000466 if (newmap == (void *)-1)
Tim Peters5ebfd362001-11-13 23:11:19 +0000467 {
468 PyErr_SetFromErrno(mmap_module_error);
469 return NULL;
470 }
471 self->data = newmap;
472 self->size = new_size;
473 Py_INCREF(Py_None);
474 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000475#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000476#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000477 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000478}
479
480static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000481mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000482{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000483 CHECK_VALID(NULL);
Thomas Wouters89f507f2006-12-13 04:49:30 +0000484 return PyInt_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000485}
486
487static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000488mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000489{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000490 Py_ssize_t offset = 0;
491 Py_ssize_t size = self->size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000492 CHECK_VALID(NULL);
Tim Petersf2882952006-02-17 01:07:39 +0000493 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000494 return NULL;
Tim Petersf2882952006-02-17 01:07:39 +0000495 if ((size_t)(offset + size) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000496 PyErr_SetString(PyExc_ValueError, "flush values out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000497 return NULL;
498 } else {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000499#ifdef MS_WINDOWS
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000500 return PyInt_FromLong((long)
Tim Peters23721ee2006-02-16 23:50:16 +0000501 FlushViewOfFile(self->data+offset, size));
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000502#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000503#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000504 /* XXX semantics of return value? */
505 /* XXX flags for msync? */
506 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000507 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000508 {
509 PyErr_SetFromErrno(mmap_module_error);
510 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000511 }
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000512 return PyInt_FromLong(0);
Tim Petersec0a5f02006-02-16 23:47:20 +0000513#endif /* UNIX */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000514 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000515}
516
517static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000518mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000519{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000520 Py_ssize_t dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000521 int how=0;
522 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000523 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
Tim Peters8f9cc292006-02-17 00:00:20 +0000524 return NULL;
525 else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000526 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000527 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000528 case 0: /* relative to start */
529 if (dist < 0)
530 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000531 where = dist;
532 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000533 case 1: /* relative to current position */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000534 if ((Py_ssize_t)self->pos + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000535 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000536 where = self->pos + dist;
537 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000538 case 2: /* relative to end */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000539 if ((Py_ssize_t)self->size + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000540 goto onoutofrange;
541 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000542 break;
543 default:
Tim Peters8f9cc292006-02-17 00:00:20 +0000544 PyErr_SetString(PyExc_ValueError, "unknown seek type");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000545 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000546 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000547 if (where > self->size)
548 goto onoutofrange;
549 self->pos = where;
Tim Peters8f9cc292006-02-17 00:00:20 +0000550 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000551 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000552 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000553
Tim Peters5ebfd362001-11-13 23:11:19 +0000554 onoutofrange:
Tim Peters8f9cc292006-02-17 00:00:20 +0000555 PyErr_SetString(PyExc_ValueError, "seek out of range");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000556 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000557}
558
559static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000560mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000561{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000562 unsigned long dest, src, count;
563 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000564 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) ||
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000565 !is_writable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000566 return NULL;
567 } else {
568 /* bounds check the values */
569 if (/* end of source after end of data?? */
570 ((src+count) > self->size)
571 /* dest will fit? */
572 || (dest+count > self->size)) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000573 PyErr_SetString(PyExc_ValueError,
574 "source or destination out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000575 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000576 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000577 memmove(self->data+dest, self->data+src, count);
578 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000579 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000580 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000581 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000582}
583
584static struct PyMethodDef mmap_object_methods[] = {
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000585 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000586 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
587 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
588 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
589 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000590 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
591 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000592 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
593 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000594 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
595 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000596 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
597 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000598 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000599};
600
601/* Functions for treating an mmap'ed file as a buffer */
602
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000603static int
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000604mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000605{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000606 CHECK_VALID(-1);
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000607 if (PyBuffer_FillInfo(view, self->data, self->size,
608 (self->access == ACCESS_READ), flags) < 0)
609 return -1;
610 self->exports++;
611 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000612}
613
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000614static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000615mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000616{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000617 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000618}
619
620static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000621mmap_object_getattr(mmap_object *self, char *name)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000622{
Tim Peters8f9cc292006-02-17 00:00:20 +0000623 return Py_FindMethod(mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000624}
625
Martin v. Löwis18e16552006-02-15 17:27:45 +0000626static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000627mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000628{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000629 CHECK_VALID(-1);
630 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000631}
632
633static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000634mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000635{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000636 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000637 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000638 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
639 return NULL;
640 }
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000641 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000642}
643
644static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000645mmap_subscript(mmap_object *self, PyObject *item)
646{
647 CHECK_VALID(NULL);
648 if (PyIndex_Check(item)) {
649 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
650 if (i == -1 && PyErr_Occurred())
651 return NULL;
652 if (i < 0)
653 i += self->size;
654 if (i < 0 || i > self->size) {
655 PyErr_SetString(PyExc_IndexError,
656 "mmap index out of range");
657 return NULL;
658 }
659 return PyBytes_FromStringAndSize(self->data + i, 1);
660 }
661 else if (PySlice_Check(item)) {
662 Py_ssize_t start, stop, step, slicelen;
663
664 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
665 &start, &stop, &step, &slicelen) < 0) {
666 return NULL;
667 }
668
669 if (slicelen <= 0)
670 return PyBytes_FromStringAndSize("", 0);
671 else if (step == 1)
672 return PyBytes_FromStringAndSize(self->data + start,
673 slicelen);
674 else {
675 char *result_buf = (char *)PyMem_Malloc(slicelen);
676 Py_ssize_t cur, i;
677 PyObject *result;
678
679 if (result_buf == NULL)
680 return PyErr_NoMemory();
681 for (cur = start, i = 0; i < slicelen;
682 cur += step, i++) {
683 result_buf[i] = self->data[cur];
684 }
685 result = PyBytes_FromStringAndSize(result_buf,
686 slicelen);
687 PyMem_Free(result_buf);
688 return result;
689 }
690 }
691 else {
692 PyErr_SetString(PyExc_TypeError,
693 "mmap indices must be integers");
694 return NULL;
695 }
696}
697
698static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000699mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000700{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000701 CHECK_VALID(NULL);
702 PyErr_SetString(PyExc_SystemError,
703 "mmaps don't support concatenation");
704 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000705}
706
707static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000708mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000709{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000710 CHECK_VALID(NULL);
711 PyErr_SetString(PyExc_SystemError,
712 "mmaps don't support repeat operation");
713 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000714}
715
716static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000717mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000718{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000719 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000720
Guido van Rossum09fdf072000-03-31 01:17:07 +0000721 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000722 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000723 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
724 return -1;
725 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000726 if (v == NULL) {
727 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000728 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000729 return -1;
730 }
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000731 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000732 PyErr_SetString(PyExc_IndexError,
Thomas Woutersed03b412007-08-28 21:37:11 +0000733 "mmap assignment must be length-1 bytes()");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000734 return -1;
735 }
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000736 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000737 return -1;
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000738 buf = PyBytes_AsString(v);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000739 self->data[i] = buf[0];
740 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000741}
742
Thomas Woutersed03b412007-08-28 21:37:11 +0000743static int
744mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
745{
746 CHECK_VALID(-1);
747
748 if (PyIndex_Check(item)) {
749 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
750 const char *buf;
751
752 if (i == -1 && PyErr_Occurred())
753 return -1;
754 if (i < 0)
755 i += self->size;
756 if (i < 0 || i > self->size) {
757 PyErr_SetString(PyExc_IndexError,
758 "mmap index out of range");
759 return -1;
760 }
761 if (value == NULL) {
762 PyErr_SetString(PyExc_TypeError,
763 "mmap object doesn't support item deletion");
764 return -1;
765 }
766 if (!PyBytes_Check(value) || PyBytes_Size(value) != 1) {
767 PyErr_SetString(PyExc_IndexError,
768 "mmap assignment must be length-1 bytes()");
769 return -1;
770 }
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000771 if (!is_writable(self))
Thomas Woutersed03b412007-08-28 21:37:11 +0000772 return -1;
773 buf = PyBytes_AsString(value);
774 self->data[i] = buf[0];
775 return 0;
776 }
777 else if (PySlice_Check(item)) {
778 Py_ssize_t start, stop, step, slicelen;
779
780 if (PySlice_GetIndicesEx((PySliceObject *)item,
781 self->size, &start, &stop,
782 &step, &slicelen) < 0) {
783 return -1;
784 }
785 if (value == NULL) {
786 PyErr_SetString(PyExc_TypeError,
787 "mmap object doesn't support slice deletion");
788 return -1;
789 }
790 if (!PyBytes_Check(value)) {
791 PyErr_SetString(PyExc_IndexError,
792 "mmap slice assignment must be bytes");
793 return -1;
794 }
795 if (PyBytes_Size(value) != slicelen) {
796 PyErr_SetString(PyExc_IndexError,
797 "mmap slice assignment is wrong size");
798 return -1;
799 }
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000800 if (!is_writable(self))
Thomas Woutersed03b412007-08-28 21:37:11 +0000801 return -1;
802
803 if (slicelen == 0)
804 return 0;
805 else if (step == 1) {
806 const char *buf = PyBytes_AsString(value);
807
808 if (buf == NULL)
809 return -1;
810 memcpy(self->data + start, buf, slicelen);
811 return 0;
812 }
813 else {
814 Py_ssize_t cur, i;
815 const char *buf = PyBytes_AsString(value);
816
817 if (buf == NULL)
818 return -1;
819 for (cur = start, i = 0; i < slicelen;
820 cur += step, i++) {
821 self->data[cur] = buf[i];
822 }
823 return 0;
824 }
825 }
826 else {
827 PyErr_SetString(PyExc_TypeError,
828 "mmap indices must be integer");
829 return -1;
830 }
831}
832
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000833static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000834 (lenfunc)mmap_length, /*sq_length*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000835 (binaryfunc)mmap_concat, /*sq_concat*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000836 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
837 (ssizeargfunc)mmap_item, /*sq_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000838 0, /*sq_slice*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000839 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000840 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000841};
842
Thomas Woutersed03b412007-08-28 21:37:11 +0000843static PyMappingMethods mmap_as_mapping = {
844 (lenfunc)mmap_length,
845 (binaryfunc)mmap_subscript,
846 (objobjargproc)mmap_ass_subscript,
847};
848
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000849static PyBufferProcs mmap_as_buffer = {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000850 (getbufferproc)mmap_buffer_getbuf,
851 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000852};
853
854static PyTypeObject mmap_object_type = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000855 PyVarObject_HEAD_INIT(0, 0) /* patched in module init */
Guido van Rossum14648392001-12-08 18:02:58 +0000856 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000857 sizeof(mmap_object), /* tp_size */
858 0, /* tp_itemsize */
859 /* methods */
860 (destructor) mmap_object_dealloc, /* tp_dealloc */
861 0, /* tp_print */
862 (getattrfunc) mmap_object_getattr, /* tp_getattr */
863 0, /* tp_setattr */
864 0, /* tp_compare */
865 0, /* tp_repr */
866 0, /* tp_as_number */
867 &mmap_as_sequence, /*tp_as_sequence*/
Thomas Woutersed03b412007-08-28 21:37:11 +0000868 &mmap_as_mapping, /*tp_as_mapping*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000869 0, /*tp_hash*/
870 0, /*tp_call*/
871 0, /*tp_str*/
872 0, /*tp_getattro*/
873 0, /*tp_setattro*/
874 &mmap_as_buffer, /*tp_as_buffer*/
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000875 Py_TPFLAGS_DEFAULT, /*tp_flags*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000876 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000877};
878
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000879
880/* extract the map size from the given PyObject
881
Thomas Wouters7e474022000-07-16 12:04:32 +0000882 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000883 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000884static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000885_GetMapSize(PyObject *o)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000886{
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000887 if (PyIndex_Check(o)) {
888 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
Guido van Rossum38fff8c2006-03-07 18:50:55 +0000889 if (i==-1 && PyErr_Occurred())
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000890 return -1;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000891 if (i < 0) {
892 PyErr_SetString(PyExc_OverflowError,
893 "memory mapped size must be positive");
894 return -1;
895 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000896 return i;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000897 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000898
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000899 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000900 return -1;
901}
902
Tim Petersec0a5f02006-02-16 23:47:20 +0000903#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000904static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000905new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000906{
Neal Norwitzb5673922002-09-05 21:48:07 +0000907#ifdef HAVE_FSTAT
908 struct stat st;
909#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000910 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000911 PyObject *map_size_obj = NULL;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000912 Py_ssize_t map_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000913 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000914 int devzero = -1;
Neal Norwitz8856fb72005-12-18 03:34:22 +0000915 int access = (int)ACCESS_DEFAULT;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +0000916 static char *keywords[] = {"fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +0000917 "flags", "prot",
Jeremy Hyltonaf68c872005-12-10 18:50:16 +0000918 "access", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000919
Tim Petersec0a5f02006-02-16 23:47:20 +0000920 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii", keywords,
Jeremy Hyltonaf68c872005-12-10 18:50:16 +0000921 &fd, &map_size_obj, &flags, &prot,
922 &access))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000923 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000924 map_size = _GetMapSize(map_size_obj);
925 if (map_size < 0)
926 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000927
Tim Petersec0a5f02006-02-16 23:47:20 +0000928 if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +0000929 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
Tim Petersec0a5f02006-02-16 23:47:20 +0000930 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000931 "mmap can't specify both access and flags, prot.");
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +0000932 switch ((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +0000933 case ACCESS_READ:
934 flags = MAP_SHARED;
935 prot = PROT_READ;
936 break;
937 case ACCESS_WRITE:
938 flags = MAP_SHARED;
939 prot = PROT_READ | PROT_WRITE;
940 break;
941 case ACCESS_COPY:
942 flags = MAP_PRIVATE;
943 prot = PROT_READ | PROT_WRITE;
944 break;
Tim Petersec0a5f02006-02-16 23:47:20 +0000945 case ACCESS_DEFAULT:
Tim Peters5ebfd362001-11-13 23:11:19 +0000946 /* use the specified or default values of flags and prot */
947 break;
948 default:
Tim Petersec0a5f02006-02-16 23:47:20 +0000949 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000950 "mmap invalid access parameter.");
951 }
Neal Norwitzb5673922002-09-05 21:48:07 +0000952
953#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +0000954# ifdef __VMS
955 /* on OpenVMS we must ensure that all bytes are written to the file */
956 fsync(fd);
957# endif
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000958 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
959 if (map_size == 0) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000960 map_size = st.st_size;
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000961 } else if ((size_t)map_size > st.st_size) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000962 PyErr_SetString(PyExc_ValueError,
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000963 "mmap length is greater than file size");
964 return NULL;
965 }
Neal Norwitzb5673922002-09-05 21:48:07 +0000966 }
967#endif
Tim Peters8f9cc292006-02-17 00:00:20 +0000968 m_obj = PyObject_New(mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000969 if (m_obj == NULL) {return NULL;}
Neal Norwitz3b4fff82006-01-11 08:54:45 +0000970 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000971 m_obj->size = (size_t) map_size;
972 m_obj->pos = (size_t) 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000973 m_obj->exports = 0;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000974 if (fd == -1) {
975 m_obj->fd = -1;
976 /* Assume the caller wants to map anonymous memory.
977 This is the same behaviour as Windows. mmap.mmap(-1, size)
978 on both Windows and Unix map anonymous memory.
979 */
980#ifdef MAP_ANONYMOUS
981 /* BSD way to map anonymous memory */
982 flags |= MAP_ANONYMOUS;
983#else
984 /* SVR4 method to map anonymous memory is to open /dev/zero */
985 fd = devzero = open("/dev/zero", O_RDWR);
986 if (devzero == -1) {
987 Py_DECREF(m_obj);
988 PyErr_SetFromErrno(mmap_module_error);
989 return NULL;
990 }
991#endif
992 } else {
993 m_obj->fd = dup(fd);
994 if (m_obj->fd == -1) {
995 Py_DECREF(m_obj);
996 PyErr_SetFromErrno(mmap_module_error);
997 return NULL;
998 }
Georg Brandl38387b82005-08-24 07:17:40 +0000999 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001000
Tim Petersec0a5f02006-02-16 23:47:20 +00001001 m_obj->data = mmap(NULL, map_size,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001002 prot, flags,
1003 fd, 0);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001004
1005 if (devzero != -1) {
1006 close(devzero);
1007 }
1008
Tim Peters5ebfd362001-11-13 23:11:19 +00001009 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +00001010 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001011 Py_DECREF(m_obj);
1012 PyErr_SetFromErrno(mmap_module_error);
1013 return NULL;
1014 }
Neal Norwitz8856fb72005-12-18 03:34:22 +00001015 m_obj->access = (access_mode)access;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001016 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001017}
1018#endif /* UNIX */
1019
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001020#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001021static PyObject *
Tim Peters5ebfd362001-11-13 23:11:19 +00001022new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001023{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001024 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001025 PyObject *map_size_obj = NULL;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001026 Py_ssize_t map_size;
Tim Peterse564e7f2006-02-16 23:46:01 +00001027 DWORD size_hi; /* upper 32 bits of m_obj->size */
1028 DWORD size_lo; /* lower 32 bits of m_obj->size */
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001029 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +00001030 DWORD dwErr = 0;
1031 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +00001032 HANDLE fh = 0;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001033 int access = (access_mode)ACCESS_DEFAULT;
Tim Peters5ebfd362001-11-13 23:11:19 +00001034 DWORD flProtect, dwDesiredAccess;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001035 static char *keywords[] = { "fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001036 "tagname",
Jeremy Hyltonaf68c872005-12-10 18:50:16 +00001037 "access", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001038
Tim Peters5ebfd362001-11-13 23:11:19 +00001039 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|zi", keywords,
Tim Petersec0a5f02006-02-16 23:47:20 +00001040 &fileno, &map_size_obj,
Tim Peters5ebfd362001-11-13 23:11:19 +00001041 &tagname, &access)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001042 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001043 }
1044
Neal Norwitz8856fb72005-12-18 03:34:22 +00001045 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001046 case ACCESS_READ:
1047 flProtect = PAGE_READONLY;
1048 dwDesiredAccess = FILE_MAP_READ;
1049 break;
1050 case ACCESS_DEFAULT: case ACCESS_WRITE:
1051 flProtect = PAGE_READWRITE;
1052 dwDesiredAccess = FILE_MAP_WRITE;
1053 break;
1054 case ACCESS_COPY:
1055 flProtect = PAGE_WRITECOPY;
1056 dwDesiredAccess = FILE_MAP_COPY;
1057 break;
1058 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001059 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001060 "mmap invalid access parameter.");
1061 }
1062
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001063 map_size = _GetMapSize(map_size_obj);
1064 if (map_size < 0)
1065 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001066
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001067 /* assume -1 and 0 both mean invalid filedescriptor
1068 to 'anonymously' map memory.
1069 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1070 XXX: Should this code be added?
1071 if (fileno == 0)
Skip Montanaro46fc3372007-08-12 11:44:53 +00001072 PyErr_WarnEx(PyExc_DeprecationWarning,
1073 "don't use 0 for anonymous memory",
1074 1);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001075 */
1076 if (fileno != -1 && fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +00001077 fh = (HANDLE)_get_osfhandle(fileno);
1078 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001079 PyErr_SetFromErrno(mmap_module_error);
1080 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001081 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +00001082 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +00001083 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001084 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001085
Tim Peters8f9cc292006-02-17 00:00:20 +00001086 m_obj = PyObject_New(mmap_object, &mmap_object_type);
1087 if (m_obj == NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +00001088 return NULL;
1089 /* Set every field to an invalid marker, so we can safely
1090 destruct the object in the face of failure */
1091 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001092 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +00001093 m_obj->map_handle = INVALID_HANDLE_VALUE;
1094 m_obj->tagname = NULL;
1095
Guido van Rossum09fdf072000-03-31 01:17:07 +00001096 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001097 /* It is necessary to duplicate the handle, so the
1098 Python code can close it on us */
1099 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001100 GetCurrentProcess(), /* source process handle */
1101 fh, /* handle to be duplicated */
1102 GetCurrentProcess(), /* target proc handle */
1103 (LPHANDLE)&m_obj->file_handle, /* result */
1104 0, /* access - ignored due to options value */
1105 FALSE, /* inherited by child processes? */
1106 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001107 dwErr = GetLastError();
1108 Py_DECREF(m_obj);
1109 PyErr_SetFromWindowsErr(dwErr);
1110 return NULL;
1111 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001112 if (!map_size) {
Martin v. Löwis15186072006-02-18 12:38:35 +00001113 DWORD low,high;
1114 low = GetFileSize(fh, &high);
1115 /* low might just happen to have the value INVALID_FILE_SIZE;
1116 so we need to check the last error also. */
1117 if (low == INVALID_FILE_SIZE &&
1118 (dwErr = GetLastError()) != NO_ERROR) {
1119 Py_DECREF(m_obj);
1120 return PyErr_SetFromWindowsErr(dwErr);
1121 }
1122
1123#if SIZEOF_SIZE_T > 4
1124 m_obj->size = (((size_t)high)<<32) + low;
1125#else
1126 if (high)
1127 /* File is too large to map completely */
1128 m_obj->size = (size_t)-1;
1129 else
1130 m_obj->size = low;
1131#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001132 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001133 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001134 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001135 }
1136 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001137 m_obj->size = map_size;
1138 }
1139
1140 /* set the initial position */
1141 m_obj->pos = (size_t) 0;
1142
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001143 m_obj->exports = 0;
Mark Hammond2cbed002000-07-30 02:22:43 +00001144 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001145 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001146 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1147 if (m_obj->tagname == NULL) {
1148 PyErr_NoMemory();
1149 Py_DECREF(m_obj);
1150 return NULL;
1151 }
1152 strcpy(m_obj->tagname, tagname);
1153 }
1154 else
1155 m_obj->tagname = NULL;
1156
Neal Norwitz8856fb72005-12-18 03:34:22 +00001157 m_obj->access = (access_mode)access;
Tim Peterse564e7f2006-02-16 23:46:01 +00001158 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
Thomas Wouters2c98a7b2006-02-17 09:59:00 +00001159 * more than 4 bytes, we need to break it apart. Else (size_t
Tim Peterse564e7f2006-02-16 23:46:01 +00001160 * consumes 4 bytes), C doesn't define what happens if we shift
1161 * right by 32, so we need different code.
1162 */
1163#if SIZEOF_SIZE_T > 4
1164 size_hi = (DWORD)(m_obj->size >> 32);
1165 size_lo = (DWORD)(m_obj->size & 0xFFFFFFFF);
1166#else
1167 size_hi = 0;
1168 size_lo = (DWORD)m_obj->size;
1169#endif
Tim Peters8f9cc292006-02-17 00:00:20 +00001170 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1171 NULL,
1172 flProtect,
1173 size_hi,
1174 size_lo,
1175 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001176 if (m_obj->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +00001177 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1178 dwDesiredAccess,
1179 0,
1180 0,
1181 0);
Tim Peters23721ee2006-02-16 23:50:16 +00001182 if (m_obj->data != NULL)
1183 return (PyObject *)m_obj;
1184 else
Tim Peters5ebfd362001-11-13 23:11:19 +00001185 dwErr = GetLastError();
Tim Peters23721ee2006-02-16 23:50:16 +00001186 } else
Guido van Rossum09fdf072000-03-31 01:17:07 +00001187 dwErr = GetLastError();
Mark Hammond2cbed002000-07-30 02:22:43 +00001188 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001189 PyErr_SetFromWindowsErr(dwErr);
Tim Peters23721ee2006-02-16 23:50:16 +00001190 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001191}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001192#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001193
1194/* List of functions exported by this module */
1195static struct PyMethodDef mmap_functions[] = {
Tim Petersec0a5f02006-02-16 23:47:20 +00001196 {"mmap", (PyCFunction) new_mmap_object,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001197 METH_VARARGS|METH_KEYWORDS},
1198 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001199};
1200
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001201static void
1202setint(PyObject *d, const char *name, long value)
1203{
1204 PyObject *o = PyInt_FromLong(value);
1205 if (o && PyDict_SetItemString(d, name, o) == 0) {
1206 Py_DECREF(o);
1207 }
1208}
1209
Mark Hammond62b1ab12002-07-23 06:31:15 +00001210PyMODINIT_FUNC
Tim Peters5ebfd362001-11-13 23:11:19 +00001211 initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001212{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001213 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001214
1215 /* Patch the object type */
Martin v. Löwis9f2e3462007-07-21 17:22:18 +00001216 Py_Type(&mmap_object_type) = &PyType_Type;
Tim Peters2caf8df2001-01-14 05:05:51 +00001217
Tim Peters8f9cc292006-02-17 00:00:20 +00001218 module = Py_InitModule("mmap", mmap_functions);
Neal Norwitz1ac754f2006-01-19 06:09:39 +00001219 if (module == NULL)
1220 return;
Tim Peters8f9cc292006-02-17 00:00:20 +00001221 dict = PyModule_GetDict(module);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001222 if (!dict)
1223 return;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001224 mmap_module_error = PyExc_EnvironmentError;
Tim Peters8f9cc292006-02-17 00:00:20 +00001225 PyDict_SetItemString(dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001226#ifdef PROT_EXEC
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001227 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001228#endif
1229#ifdef PROT_READ
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001230 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001231#endif
1232#ifdef PROT_WRITE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001233 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001234#endif
1235
1236#ifdef MAP_SHARED
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001237 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001238#endif
1239#ifdef MAP_PRIVATE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001240 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001241#endif
1242#ifdef MAP_DENYWRITE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001243 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001244#endif
1245#ifdef MAP_EXECUTABLE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001246 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001247#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001248#ifdef MAP_ANONYMOUS
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001249 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1250 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001251#endif
1252
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001253 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001254
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001255 setint(dict, "ACCESS_READ", ACCESS_READ);
1256 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1257 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001258}