blob: f58e0f184cb44112baad07cdf04bf597fb7bba86 [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 /
12 / Note: This module currently only deals with 32-bit file
13 / sizes.
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
Guido van Rossum09fdf072000-03-31 01:17:07 +000021#include <Python.h>
22
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000023#ifndef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000024#define UNIX
25#endif
26
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000027#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000028#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000029static int
30my_getpagesize(void)
31{
Tim Peters5ebfd362001-11-13 23:11:19 +000032 SYSTEM_INFO si;
33 GetSystemInfo(&si);
34 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000035}
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000036#endif
37
38#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000039#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000040#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000041
Fred Drake145f96e2000-10-01 17:50:46 +000042#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
43static int
44my_getpagesize(void)
45{
Tim Peters5ebfd362001-11-13 23:11:19 +000046 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000047}
48#else
49#define my_getpagesize getpagesize
50#endif
51
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000052#endif /* UNIX */
53
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000054#include <string.h>
55#include <sys/types.h>
56
57static PyObject *mmap_module_error;
58
Tim Peters5ebfd362001-11-13 23:11:19 +000059typedef enum
60{
61 ACCESS_DEFAULT,
62 ACCESS_READ,
63 ACCESS_WRITE,
64 ACCESS_COPY
65} access_mode;
66
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000067typedef struct {
Guido van Rossum09fdf072000-03-31 01:17:07 +000068 PyObject_HEAD
69 char * data;
70 size_t size;
71 size_t pos;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000072
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000073#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +000074 HANDLE map_handle;
Mark Hammond071864a2000-07-30 02:46:26 +000075 HANDLE file_handle;
Guido van Rossum09fdf072000-03-31 01:17:07 +000076 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000077#endif
78
79#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000080 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000081#endif
Tim Peters5ebfd362001-11-13 23:11:19 +000082
83 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000084} mmap_object;
85
Tim Peters5ebfd362001-11-13 23:11:19 +000086
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000087static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +000088mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000089{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000090#ifdef MS_WINDOWS
Mark Hammond2cbed002000-07-30 02:22:43 +000091 if (m_obj->data != NULL)
92 UnmapViewOfFile (m_obj->data);
93 if (m_obj->map_handle != INVALID_HANDLE_VALUE)
94 CloseHandle (m_obj->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +000095 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
96 CloseHandle (m_obj->file_handle);
Mark Hammond2cbed002000-07-30 02:22:43 +000097 if (m_obj->tagname)
98 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000099#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000100
101#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000102 if (m_obj->data!=NULL) {
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000103 msync(m_obj->data, m_obj->size, MS_SYNC);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000104 munmap(m_obj->data, m_obj->size);
105 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000106#endif /* UNIX */
107
Guido van Rossumb18618d2000-05-03 23:44:39 +0000108 PyObject_Del(m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000109}
110
111static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000112mmap_close_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000113{
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000114 if (!PyArg_ParseTuple(args, ":close"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000115 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000116#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000117 /* For each resource we maintain, we need to check
118 the value is valid, and if so, free the resource
119 and set the member value to an invalid value so
120 the dealloc does not attempt to resource clearing
121 again.
122 TODO - should we check for errors in the close operations???
123 */
124 if (self->data != NULL) {
125 UnmapViewOfFile (self->data);
126 self->data = NULL;
127 }
128 if (self->map_handle != INVALID_HANDLE_VALUE) {
129 CloseHandle (self->map_handle);
130 self->map_handle = INVALID_HANDLE_VALUE;
131 }
132 if (self->file_handle != INVALID_HANDLE_VALUE) {
133 CloseHandle (self->file_handle);
134 self->file_handle = INVALID_HANDLE_VALUE;
135 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000136#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000137
138#ifdef UNIX
Neal Norwitze604c022003-01-10 20:52:16 +0000139 if (self->data != NULL) {
140 munmap(self->data, self->size);
141 self->data = NULL;
142 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000143#endif
144
Guido van Rossum09fdf072000-03-31 01:17:07 +0000145 Py_INCREF (Py_None);
146 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000147}
148
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000149#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +0000150#define CHECK_VALID(err) \
151do { \
Guido van Rossum69c2b882003-04-09 19:31:02 +0000152 if (self->map_handle == INVALID_HANDLE_VALUE) { \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000153 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
154 return err; \
155 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000156} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000157#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000158
159#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000160#define CHECK_VALID(err) \
161do { \
162 if (self->data == NULL) { \
163 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
164 return err; \
165 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000166} while (0)
167#endif /* UNIX */
168
169static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000170mmap_read_byte_method(mmap_object *self,
171 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000172{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000173 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000174 if (!PyArg_ParseTuple(args, ":read_byte"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000175 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000176 if (self->pos < self->size) {
Tim Petersd6283b82001-05-09 18:48:26 +0000177 char value = self->data[self->pos];
Guido van Rossum09fdf072000-03-31 01:17:07 +0000178 self->pos += 1;
Tim Petersd6283b82001-05-09 18:48:26 +0000179 return Py_BuildValue("c", value);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000180 } else {
181 PyErr_SetString (PyExc_ValueError, "read byte out of range");
182 return NULL;
183 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000184}
185
186static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000187mmap_read_line_method(mmap_object *self,
Tim Peters5ebfd362001-11-13 23:11:19 +0000188 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000189{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000190 char *start = self->data+self->pos;
191 char *eof = self->data+self->size;
192 char *eol;
193 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000194
Guido van Rossum09fdf072000-03-31 01:17:07 +0000195 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000196 if (!PyArg_ParseTuple(args, ":readline"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000197 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000198
Fred Drake56a87a02000-04-04 18:17:35 +0000199 eol = memchr(start, '\n', self->size - self->pos);
200 if (!eol)
201 eol = eof;
202 else
203 ++eol; /* we're interested in the position after the
204 newline. */
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000205 result = PyString_FromStringAndSize(start, (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000206 self->pos += (eol - start);
207 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000208}
209
210static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000211mmap_read_method(mmap_object *self,
212 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000213{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000214 long num_bytes;
215 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000216
Guido van Rossum09fdf072000-03-31 01:17:07 +0000217 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000218 if (!PyArg_ParseTuple(args, "l:read", &num_bytes))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000219 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000220
Guido van Rossum09fdf072000-03-31 01:17:07 +0000221 /* silently 'adjust' out-of-range requests */
222 if ((self->pos + num_bytes) > self->size) {
223 num_bytes -= (self->pos+num_bytes) - self->size;
224 }
225 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
226 self->pos += num_bytes;
227 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000228}
229
230static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000231mmap_find_method(mmap_object *self,
232 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000233{
Tim Petersd401edd2001-05-14 23:19:12 +0000234 long start = self->pos;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000235 char *needle;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000236 int len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000237
Guido van Rossum09fdf072000-03-31 01:17:07 +0000238 CHECK_VALID(NULL);
Tim Petersd401edd2001-05-14 23:19:12 +0000239 if (!PyArg_ParseTuple (args, "s#|l:find", &needle, &len, &start)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000240 return NULL;
241 } else {
Greg Stein834f4dd2001-05-14 09:32:26 +0000242 char *p;
243 char *e = self->data + self->size;
244
245 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000246 start += self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000247 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000248 start = 0;
Tim Petersd401edd2001-05-14 23:19:12 +0000249 else if ((size_t)start > self->size)
Tim Peters5ebfd362001-11-13 23:11:19 +0000250 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000251
Tim Petersc9ffa062002-03-08 05:43:32 +0000252 for (p = self->data + start; p + len <= e; ++p) {
253 int i;
254 for (i = 0; i < len && needle[i] == p[i]; ++i)
255 /* nothing */;
256 if (i == len) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000257 return Py_BuildValue (
Tim Petersd401edd2001-05-14 23:19:12 +0000258 "l",
259 (long) (p - self->data));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000260 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000261 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000262 return Py_BuildValue ("l", (long) -1);
263 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000264}
265
Tim Peters5ebfd362001-11-13 23:11:19 +0000266static int
267is_writeable(mmap_object *self)
268{
269 if (self->access != ACCESS_READ)
270 return 1;
271 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
272 return 0;
273}
274
275static int
276is_resizeable(mmap_object *self)
277{
278 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
279 return 1;
280 PyErr_Format(PyExc_TypeError,
281 "mmap can't resize a readonly or copy-on-write memory map.");
282 return 0;
283}
284
285
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000286static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000287mmap_write_method(mmap_object *self,
288 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000289{
Neal Norwitz4d933fe2003-02-07 19:44:56 +0000290 int length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000291 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000292
Guido van Rossum09fdf072000-03-31 01:17:07 +0000293 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000294 if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000295 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000296
Tim Peters5ebfd362001-11-13 23:11:19 +0000297 if (!is_writeable(self))
298 return NULL;
299
Guido van Rossum09fdf072000-03-31 01:17:07 +0000300 if ((self->pos + length) > self->size) {
301 PyErr_SetString (PyExc_ValueError, "data out of range");
302 return NULL;
303 }
304 memcpy (self->data+self->pos, data, length);
305 self->pos = self->pos+length;
306 Py_INCREF (Py_None);
307 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000308}
309
310static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000311mmap_write_byte_method(mmap_object *self,
312 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000313{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000314 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000315
Guido van Rossum09fdf072000-03-31 01:17:07 +0000316 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000317 if (!PyArg_ParseTuple (args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000318 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000319
Tim Peters5ebfd362001-11-13 23:11:19 +0000320 if (!is_writeable(self))
321 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000322 *(self->data+self->pos) = value;
323 self->pos += 1;
324 Py_INCREF (Py_None);
325 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000326}
Tim Peters5ebfd362001-11-13 23:11:19 +0000327
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000328static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000329mmap_size_method(mmap_object *self,
330 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000331{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000332 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000333 if (!PyArg_ParseTuple(args, ":size"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000334 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000335
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000336#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000337 if (self->file_handle != INVALID_HANDLE_VALUE) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000338 return (Py_BuildValue (
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000339 "l", (long)
Mark Hammond071864a2000-07-30 02:46:26 +0000340 GetFileSize (self->file_handle, NULL)));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000341 } else {
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000342 return (Py_BuildValue ("l", (long) self->size) );
Guido van Rossum09fdf072000-03-31 01:17:07 +0000343 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000344#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000345
346#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000347 {
348 struct stat buf;
349 if (-1 == fstat(self->fd, &buf)) {
350 PyErr_SetFromErrno(mmap_module_error);
351 return NULL;
352 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000353 return (Py_BuildValue ("l", (long) buf.st_size) );
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000354 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000355#endif /* UNIX */
356}
357
358/* This assumes that you want the entire file mapped,
359 / and when recreating the map will make the new file
360 / have the new size
361 /
362 / Is this really necessary? This could easily be done
363 / from python by just closing and re-opening with the
364 / new size?
365 */
366
367static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000368mmap_resize_method(mmap_object *self,
369 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000370{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000371 unsigned long new_size;
372 CHECK_VALID(NULL);
Tim Peters5ebfd362001-11-13 23:11:19 +0000373 if (!PyArg_ParseTuple (args, "l:resize", &new_size) ||
374 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000375 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000376#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +0000377 } else {
378 DWORD dwErrCode = 0;
379 /* First, unmap the file view */
380 UnmapViewOfFile (self->data);
381 /* Close the mapping object */
Mark Hammond071864a2000-07-30 02:46:26 +0000382 CloseHandle (self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000383 /* Move to the desired EOF position */
Mark Hammond071864a2000-07-30 02:46:26 +0000384 SetFilePointer (self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000385 new_size, NULL, FILE_BEGIN);
386 /* Change the size of the file */
Mark Hammond071864a2000-07-30 02:46:26 +0000387 SetEndOfFile (self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000388 /* Create another mapping object and remap the file view */
389 self->map_handle = CreateFileMapping (
Mark Hammond071864a2000-07-30 02:46:26 +0000390 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000391 NULL,
392 PAGE_READWRITE,
393 0,
394 new_size,
395 self->tagname);
396 if (self->map_handle != NULL) {
397 self->data = (char *) MapViewOfFile (self->map_handle,
398 FILE_MAP_WRITE,
399 0,
400 0,
401 0);
402 if (self->data != NULL) {
403 self->size = new_size;
404 Py_INCREF (Py_None);
405 return Py_None;
406 } else {
407 dwErrCode = GetLastError();
408 }
409 } else {
410 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000411 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000412 PyErr_SetFromWindowsErr(dwErrCode);
413 return (NULL);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000414#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000415
416#ifdef UNIX
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000417#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000418 } else {
419 PyErr_SetString(PyExc_SystemError,
420 "mmap: resizing not available--no mremap()");
421 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000422#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000423 } else {
Georg Brandl38387b82005-08-24 07:17:40 +0000424 if (ftruncate(self->fd, new_size) == -1) {
425 PyErr_SetFromErrno(mmap_module_error);
426 return NULL;
427 }
428
Tim Peters5ebfd362001-11-13 23:11:19 +0000429 void *newmap;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000430
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000431#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000432 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000433#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000434 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000435#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000436 if (newmap == (void *)-1)
437 {
438 PyErr_SetFromErrno(mmap_module_error);
439 return NULL;
440 }
441 self->data = newmap;
442 self->size = new_size;
443 Py_INCREF(Py_None);
444 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000445#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000446#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000447 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000448}
449
450static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000451mmap_tell_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000452{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000453 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000454 if (!PyArg_ParseTuple(args, ":tell"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000455 return NULL;
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000456 return (Py_BuildValue ("l", (long) self->pos) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000457}
458
459static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000460mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000461{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000462 size_t offset = 0;
463 size_t size = self->size;
464 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000465 if (!PyArg_ParseTuple (args, "|ll:flush", &offset, &size)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000466 return NULL;
467 } else if ((offset + size) > self->size) {
468 PyErr_SetString (PyExc_ValueError,
469 "flush values out of range");
470 return NULL;
471 } else {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000472#ifdef MS_WINDOWS
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000473 return (Py_BuildValue("l", (long)
474 FlushViewOfFile(self->data+offset, size)));
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000475#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000476#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000477 /* XXX semantics of return value? */
478 /* XXX flags for msync? */
479 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000480 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000481 {
482 PyErr_SetFromErrno(mmap_module_error);
483 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000484 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000485 return Py_BuildValue ("l", (long) 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000486#endif /* UNIX */
487 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000488}
489
490static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000491mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000492{
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000493 int dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000494 int how=0;
495 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000496 if (!PyArg_ParseTuple (args, "i|i:seek", &dist, &how)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000497 return(NULL);
498 } else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000499 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000500 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000501 case 0: /* relative to start */
502 if (dist < 0)
503 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000504 where = dist;
505 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000506 case 1: /* relative to current position */
507 if ((int)self->pos + dist < 0)
508 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000509 where = self->pos + dist;
510 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000511 case 2: /* relative to end */
512 if ((int)self->size + dist < 0)
513 goto onoutofrange;
514 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000515 break;
516 default:
517 PyErr_SetString (PyExc_ValueError,
518 "unknown seek type");
519 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000520 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000521 if (where > self->size)
522 goto onoutofrange;
523 self->pos = where;
524 Py_INCREF (Py_None);
525 return (Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000526 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000527
Tim Peters5ebfd362001-11-13 23:11:19 +0000528 onoutofrange:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000529 PyErr_SetString (PyExc_ValueError, "seek out of range");
530 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000531}
532
533static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000534mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000535{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000536 unsigned long dest, src, count;
537 CHECK_VALID(NULL);
Tim Peters5ebfd362001-11-13 23:11:19 +0000538 if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count) ||
539 !is_writeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000540 return NULL;
541 } else {
542 /* bounds check the values */
543 if (/* end of source after end of data?? */
544 ((src+count) > self->size)
545 /* dest will fit? */
546 || (dest+count > self->size)) {
547 PyErr_SetString (PyExc_ValueError,
548 "source or destination out of range");
549 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000550 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000551 memmove (self->data+dest, self->data+src, count);
552 Py_INCREF (Py_None);
553 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000554 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000555 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000556}
557
558static struct PyMethodDef mmap_object_methods[] = {
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000559 {"close", (PyCFunction) mmap_close_method, METH_VARARGS},
560 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
561 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
562 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
563 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
564 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_VARARGS},
565 {"readline", (PyCFunction) mmap_read_line_method, METH_VARARGS},
566 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
567 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
568 {"size", (PyCFunction) mmap_size_method, METH_VARARGS},
569 {"tell", (PyCFunction) mmap_tell_method, METH_VARARGS},
570 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
571 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000572 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000573};
574
575/* Functions for treating an mmap'ed file as a buffer */
576
577static int
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000578mmap_buffer_getreadbuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000579{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000580 CHECK_VALID(-1);
581 if ( index != 0 ) {
582 PyErr_SetString(PyExc_SystemError,
583 "Accessing non-existent mmap segment");
584 return -1;
585 }
586 *ptr = self->data;
587 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000588}
589
590static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000591mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000592{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000593 CHECK_VALID(-1);
594 if ( index != 0 ) {
595 PyErr_SetString(PyExc_SystemError,
596 "Accessing non-existent mmap segment");
597 return -1;
598 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000599 if (!is_writeable(self))
600 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000601 *ptr = self->data;
602 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000603}
604
605static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000606mmap_buffer_getsegcount(mmap_object *self, int *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000607{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000608 CHECK_VALID(-1);
609 if (lenp)
610 *lenp = self->size;
611 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000612}
613
614static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000615mmap_buffer_getcharbuffer(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000616{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000617 if ( index != 0 ) {
618 PyErr_SetString(PyExc_SystemError,
619 "accessing non-existent buffer segment");
620 return -1;
621 }
622 *ptr = (const char *)self->data;
623 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000624}
625
626static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000627mmap_object_getattr(mmap_object *self, char *name)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000628{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000629 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000630}
631
632static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000633mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000634{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000635 CHECK_VALID(-1);
636 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000637}
638
639static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000640mmap_item(mmap_object *self, int i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000641{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000642 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000643 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000644 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
645 return NULL;
646 }
647 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000648}
649
650static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000651mmap_slice(mmap_object *self, int ilow, int ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000652{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000653 CHECK_VALID(NULL);
654 if (ilow < 0)
655 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000656 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000657 ilow = self->size;
658 if (ihigh < 0)
659 ihigh = 0;
660 if (ihigh < ilow)
661 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000662 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000663 ihigh = self->size;
664
665 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000666}
667
668static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000669mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000670{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000671 CHECK_VALID(NULL);
672 PyErr_SetString(PyExc_SystemError,
673 "mmaps don't support concatenation");
674 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000675}
676
677static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000678mmap_repeat(mmap_object *self, int n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000679{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000680 CHECK_VALID(NULL);
681 PyErr_SetString(PyExc_SystemError,
682 "mmaps don't support repeat operation");
683 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000684}
685
686static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000687mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000688{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000689 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000690
Guido van Rossum09fdf072000-03-31 01:17:07 +0000691 CHECK_VALID(-1);
692 if (ilow < 0)
693 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000694 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000695 ilow = self->size;
696 if (ihigh < 0)
697 ihigh = 0;
698 if (ihigh < ilow)
699 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000700 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000701 ihigh = self->size;
702
Thomas Wouters1baac722001-07-16 15:47:36 +0000703 if (v == NULL) {
704 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000705 "mmap object doesn't support slice deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000706 return -1;
707 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000708 if (! (PyString_Check(v)) ) {
709 PyErr_SetString(PyExc_IndexError,
710 "mmap slice assignment must be a string");
711 return -1;
712 }
713 if ( PyString_Size(v) != (ihigh - ilow) ) {
714 PyErr_SetString(PyExc_IndexError,
715 "mmap slice assignment is wrong size");
716 return -1;
717 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000718 if (!is_writeable(self))
719 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000720 buf = PyString_AsString(v);
721 memcpy(self->data + ilow, buf, ihigh-ilow);
722 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000723}
724
725static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000726mmap_ass_item(mmap_object *self, int i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000727{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000728 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000729
Guido van Rossum09fdf072000-03-31 01:17:07 +0000730 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000731 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000732 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
733 return -1;
734 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000735 if (v == NULL) {
736 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000737 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000738 return -1;
739 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000740 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
741 PyErr_SetString(PyExc_IndexError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000742 "mmap assignment must be single-character string");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000743 return -1;
744 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000745 if (!is_writeable(self))
746 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000747 buf = PyString_AsString(v);
748 self->data[i] = buf[0];
749 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000750}
751
752static PySequenceMethods mmap_as_sequence = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000753 (inquiry)mmap_length, /*sq_length*/
754 (binaryfunc)mmap_concat, /*sq_concat*/
755 (intargfunc)mmap_repeat, /*sq_repeat*/
756 (intargfunc)mmap_item, /*sq_item*/
757 (intintargfunc)mmap_slice, /*sq_slice*/
758 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
759 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000760};
761
762static PyBufferProcs mmap_as_buffer = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000763 (getreadbufferproc)mmap_buffer_getreadbuf,
764 (getwritebufferproc)mmap_buffer_getwritebuf,
765 (getsegcountproc)mmap_buffer_getsegcount,
766 (getcharbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000767};
768
769static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000770 PyObject_HEAD_INIT(0) /* patched in module init */
771 0, /* ob_size */
Guido van Rossum14648392001-12-08 18:02:58 +0000772 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000773 sizeof(mmap_object), /* tp_size */
774 0, /* tp_itemsize */
775 /* methods */
776 (destructor) mmap_object_dealloc, /* tp_dealloc */
777 0, /* tp_print */
778 (getattrfunc) mmap_object_getattr, /* tp_getattr */
779 0, /* tp_setattr */
780 0, /* tp_compare */
781 0, /* tp_repr */
782 0, /* tp_as_number */
783 &mmap_as_sequence, /*tp_as_sequence*/
784 0, /*tp_as_mapping*/
785 0, /*tp_hash*/
786 0, /*tp_call*/
787 0, /*tp_str*/
788 0, /*tp_getattro*/
789 0, /*tp_setattro*/
790 &mmap_as_buffer, /*tp_as_buffer*/
791 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
792 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000793};
794
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000795
796/* extract the map size from the given PyObject
797
798 The map size is restricted to [0, INT_MAX] because this is the current
799 Python limitation on object sizes. Although the mmap object *could* handle
800 a larger map size, there is no point because all the useful operations
801 (len(), slicing(), sequence indexing) are limited by a C int.
802
Thomas Wouters7e474022000-07-16 12:04:32 +0000803 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000804 success, the map size is returned. */
805static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000806_GetMapSize(PyObject *o)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000807{
808 if (PyInt_Check(o)) {
809 long i = PyInt_AsLong(o);
810 if (PyErr_Occurred())
811 return -1;
812 if (i < 0)
813 goto onnegoverflow;
814 if (i > INT_MAX)
815 goto onposoverflow;
816 return (int)i;
817 }
818 else if (PyLong_Check(o)) {
819 long i = PyLong_AsLong(o);
820 if (PyErr_Occurred()) {
821 /* yes negative overflow is mistaken for positive overflow
822 but not worth the trouble to check sign of 'i' */
823 if (PyErr_ExceptionMatches(PyExc_OverflowError))
824 goto onposoverflow;
825 else
826 return -1;
827 }
828 if (i < 0)
829 goto onnegoverflow;
830 if (i > INT_MAX)
831 goto onposoverflow;
832 return (int)i;
833 }
834 else {
835 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000836 "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000837 return -1;
838 }
839
Tim Peters5ebfd362001-11-13 23:11:19 +0000840 onnegoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000841 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000842 "memory mapped size must be positive");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000843 return -1;
844
Tim Peters5ebfd362001-11-13 23:11:19 +0000845 onposoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000846 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000847 "memory mapped size is too large (limited by C int)");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000848 return -1;
849}
850
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000851#ifdef UNIX
852static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000853new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000854{
Neal Norwitzb5673922002-09-05 21:48:07 +0000855#ifdef HAVE_FSTAT
856 struct stat st;
857#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000858 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000859 PyObject *map_size_obj = NULL;
860 int map_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000861 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Tim Peters5ebfd362001-11-13 23:11:19 +0000862 access_mode access = ACCESS_DEFAULT;
863 char *keywords[] = {"fileno", "length",
864 "flags", "prot",
865 "access", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000866
Tim Peters5ebfd362001-11-13 23:11:19 +0000867 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii", keywords,
868 &fd, &map_size_obj, &flags, &prot, &access))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000869 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000870 map_size = _GetMapSize(map_size_obj);
871 if (map_size < 0)
872 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000873
874 if ((access != ACCESS_DEFAULT) &&
875 ((flags != MAP_SHARED) || ( prot != (PROT_WRITE | PROT_READ))))
876 return PyErr_Format(PyExc_ValueError,
877 "mmap can't specify both access and flags, prot.");
878 switch(access) {
879 case ACCESS_READ:
880 flags = MAP_SHARED;
881 prot = PROT_READ;
882 break;
883 case ACCESS_WRITE:
884 flags = MAP_SHARED;
885 prot = PROT_READ | PROT_WRITE;
886 break;
887 case ACCESS_COPY:
888 flags = MAP_PRIVATE;
889 prot = PROT_READ | PROT_WRITE;
890 break;
891 case ACCESS_DEFAULT:
892 /* use the specified or default values of flags and prot */
893 break;
894 default:
895 return PyErr_Format(PyExc_ValueError,
896 "mmap invalid access parameter.");
897 }
Neal Norwitzb5673922002-09-05 21:48:07 +0000898
899#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +0000900# ifdef __VMS
901 /* on OpenVMS we must ensure that all bytes are written to the file */
902 fsync(fd);
903# endif
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000904 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
905 if (map_size == 0) {
906 map_size = (int)st.st_size;
907 } else if ((size_t)map_size > st.st_size) {
908 PyErr_SetString(PyExc_ValueError,
909 "mmap length is greater than file size");
910 return NULL;
911 }
Neal Norwitzb5673922002-09-05 21:48:07 +0000912 }
913#endif
Guido van Rossumb18618d2000-05-03 23:44:39 +0000914 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000915 if (m_obj == NULL) {return NULL;}
916 m_obj->size = (size_t) map_size;
917 m_obj->pos = (size_t) 0;
Georg Brandl38387b82005-08-24 07:17:40 +0000918 m_obj->fd = dup(fd);
919 if (m_obj->fd == -1) {
920 Py_DECREF(m_obj);
921 PyErr_SetFromErrno(mmap_module_error);
922 return NULL;
923 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000924 m_obj->data = mmap(NULL, map_size,
925 prot, flags,
926 fd, 0);
Tim Peters5ebfd362001-11-13 23:11:19 +0000927 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +0000928 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000929 Py_DECREF(m_obj);
930 PyErr_SetFromErrno(mmap_module_error);
931 return NULL;
932 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000933 m_obj->access = access;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000934 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000935}
936#endif /* UNIX */
937
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000938#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000939static PyObject *
Tim Peters5ebfd362001-11-13 23:11:19 +0000940new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000941{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000942 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000943 PyObject *map_size_obj = NULL;
944 int map_size;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000945 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +0000946 DWORD dwErr = 0;
947 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +0000948 HANDLE fh = 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000949 access_mode access = ACCESS_DEFAULT;
950 DWORD flProtect, dwDesiredAccess;
951 char *keywords[] = { "fileno", "length",
952 "tagname",
953 "access", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000954
Tim Peters5ebfd362001-11-13 23:11:19 +0000955 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|zi", keywords,
956 &fileno, &map_size_obj,
957 &tagname, &access)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000958 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000959 }
960
961 switch(access) {
962 case ACCESS_READ:
963 flProtect = PAGE_READONLY;
964 dwDesiredAccess = FILE_MAP_READ;
965 break;
966 case ACCESS_DEFAULT: case ACCESS_WRITE:
967 flProtect = PAGE_READWRITE;
968 dwDesiredAccess = FILE_MAP_WRITE;
969 break;
970 case ACCESS_COPY:
971 flProtect = PAGE_WRITECOPY;
972 dwDesiredAccess = FILE_MAP_COPY;
973 break;
974 default:
975 return PyErr_Format(PyExc_ValueError,
976 "mmap invalid access parameter.");
977 }
978
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000979 map_size = _GetMapSize(map_size_obj);
980 if (map_size < 0)
981 return NULL;
982
Guido van Rossum09fdf072000-03-31 01:17:07 +0000983 /* if an actual filename has been specified */
984 if (fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +0000985 fh = (HANDLE)_get_osfhandle(fileno);
986 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +0000987 PyErr_SetFromErrno(mmap_module_error);
988 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000989 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +0000990 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +0000991 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000992 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000993
Guido van Rossumb18618d2000-05-03 23:44:39 +0000994 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Mark Hammond2cbed002000-07-30 02:22:43 +0000995 if (m_obj==NULL)
996 return NULL;
997 /* Set every field to an invalid marker, so we can safely
998 destruct the object in the face of failure */
999 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001000 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +00001001 m_obj->map_handle = INVALID_HANDLE_VALUE;
1002 m_obj->tagname = NULL;
1003
Guido van Rossum09fdf072000-03-31 01:17:07 +00001004 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001005 /* It is necessary to duplicate the handle, so the
1006 Python code can close it on us */
1007 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001008 GetCurrentProcess(), /* source process handle */
1009 fh, /* handle to be duplicated */
1010 GetCurrentProcess(), /* target proc handle */
1011 (LPHANDLE)&m_obj->file_handle, /* result */
1012 0, /* access - ignored due to options value */
1013 FALSE, /* inherited by child processes? */
1014 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001015 dwErr = GetLastError();
1016 Py_DECREF(m_obj);
1017 PyErr_SetFromWindowsErr(dwErr);
1018 return NULL;
1019 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001020 if (!map_size) {
Mark Hammond071864a2000-07-30 02:46:26 +00001021 m_obj->size = GetFileSize (fh, NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001022 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001023 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001024 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001025 }
1026 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001027 m_obj->size = map_size;
1028 }
1029
1030 /* set the initial position */
1031 m_obj->pos = (size_t) 0;
1032
Mark Hammond2cbed002000-07-30 02:22:43 +00001033 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001034 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001035 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1036 if (m_obj->tagname == NULL) {
1037 PyErr_NoMemory();
1038 Py_DECREF(m_obj);
1039 return NULL;
1040 }
1041 strcpy(m_obj->tagname, tagname);
1042 }
1043 else
1044 m_obj->tagname = NULL;
1045
Tim Peters5ebfd362001-11-13 23:11:19 +00001046 m_obj->access = access;
Mark Hammond071864a2000-07-30 02:46:26 +00001047 m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001048 NULL,
Tim Peters5ebfd362001-11-13 23:11:19 +00001049 flProtect,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001050 0,
1051 m_obj->size,
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001052 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001053 if (m_obj->map_handle != NULL) {
1054 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
Tim Peters5ebfd362001-11-13 23:11:19 +00001055 dwDesiredAccess,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001056 0,
1057 0,
1058 0);
1059 if (m_obj->data != NULL) {
1060 return ((PyObject *) m_obj);
1061 } else {
Tim Peters5ebfd362001-11-13 23:11:19 +00001062 dwErr = GetLastError();
Guido van Rossum09fdf072000-03-31 01:17:07 +00001063 }
1064 } else {
1065 dwErr = GetLastError();
1066 }
Mark Hammond2cbed002000-07-30 02:22:43 +00001067 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001068 PyErr_SetFromWindowsErr(dwErr);
1069 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001070}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001071#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001072
1073/* List of functions exported by this module */
1074static struct PyMethodDef mmap_functions[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001075 {"mmap", (PyCFunction) new_mmap_object,
1076 METH_VARARGS|METH_KEYWORDS},
1077 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001078};
1079
Mark Hammond62b1ab12002-07-23 06:31:15 +00001080PyMODINIT_FUNC
Tim Peters5ebfd362001-11-13 23:11:19 +00001081 initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001082{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001083 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001084
1085 /* Patch the object type */
1086 mmap_object_type.ob_type = &PyType_Type;
1087
Guido van Rossum09fdf072000-03-31 01:17:07 +00001088 module = Py_InitModule ("mmap", mmap_functions);
1089 dict = PyModule_GetDict (module);
1090 mmap_module_error = PyExc_EnvironmentError;
1091 Py_INCREF(mmap_module_error);
1092 PyDict_SetItemString (dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001093#ifdef PROT_EXEC
Guido van Rossum09fdf072000-03-31 01:17:07 +00001094 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001095#endif
1096#ifdef PROT_READ
Guido van Rossum09fdf072000-03-31 01:17:07 +00001097 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001098#endif
1099#ifdef PROT_WRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001100 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001101#endif
1102
1103#ifdef MAP_SHARED
Guido van Rossum09fdf072000-03-31 01:17:07 +00001104 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001105#endif
1106#ifdef MAP_PRIVATE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001107 PyDict_SetItemString (dict, "MAP_PRIVATE",
1108 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001109#endif
1110#ifdef MAP_DENYWRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001111 PyDict_SetItemString (dict, "MAP_DENYWRITE",
1112 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001113#endif
1114#ifdef MAP_EXECUTABLE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001115 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
1116 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001117#endif
1118#ifdef MAP_ANON
Guido van Rossum09fdf072000-03-31 01:17:07 +00001119 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
1120 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
1121 PyInt_FromLong(MAP_ANON) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001122#endif
1123
Guido van Rossum09fdf072000-03-31 01:17:07 +00001124 PyDict_SetItemString (dict, "PAGESIZE",
Fred Drake145f96e2000-10-01 17:50:46 +00001125 PyInt_FromLong( (long)my_getpagesize() ) );
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001126
Tim Peters5ebfd362001-11-13 23:11:19 +00001127 PyDict_SetItemString (dict, "ACCESS_READ",
1128 PyInt_FromLong(ACCESS_READ));
1129 PyDict_SetItemString (dict, "ACCESS_WRITE",
1130 PyInt_FromLong(ACCESS_WRITE));
1131 PyDict_SetItemString (dict, "ACCESS_COPY",
1132 PyInt_FromLong(ACCESS_COPY));
1133}