blob: e1a2f4238b930b9c2709d5e55478d99c32972524 [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 {
424 void *newmap;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000425
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000426#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000427 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000428#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000429 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000430#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000431 if (newmap == (void *)-1)
432 {
433 PyErr_SetFromErrno(mmap_module_error);
434 return NULL;
435 }
436 self->data = newmap;
437 self->size = new_size;
438 Py_INCREF(Py_None);
439 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000440#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000441#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000442 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000443}
444
445static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000446mmap_tell_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000447{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000448 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000449 if (!PyArg_ParseTuple(args, ":tell"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000450 return NULL;
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000451 return (Py_BuildValue ("l", (long) self->pos) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000452}
453
454static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000455mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000456{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000457 size_t offset = 0;
458 size_t size = self->size;
459 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000460 if (!PyArg_ParseTuple (args, "|ll:flush", &offset, &size)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000461 return NULL;
462 } else if ((offset + size) > self->size) {
463 PyErr_SetString (PyExc_ValueError,
464 "flush values out of range");
465 return NULL;
466 } else {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000467#ifdef MS_WINDOWS
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000468 return (Py_BuildValue("l", (long)
469 FlushViewOfFile(self->data+offset, size)));
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000470#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000471#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000472 /* XXX semantics of return value? */
473 /* XXX flags for msync? */
474 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000475 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000476 {
477 PyErr_SetFromErrno(mmap_module_error);
478 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000479 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000480 return Py_BuildValue ("l", (long) 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000481#endif /* UNIX */
482 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000483}
484
485static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000486mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000487{
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000488 int dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000489 int how=0;
490 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000491 if (!PyArg_ParseTuple (args, "i|i:seek", &dist, &how)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000492 return(NULL);
493 } else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000494 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000495 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000496 case 0: /* relative to start */
497 if (dist < 0)
498 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000499 where = dist;
500 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000501 case 1: /* relative to current position */
502 if ((int)self->pos + dist < 0)
503 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000504 where = self->pos + dist;
505 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000506 case 2: /* relative to end */
507 if ((int)self->size + dist < 0)
508 goto onoutofrange;
509 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000510 break;
511 default:
512 PyErr_SetString (PyExc_ValueError,
513 "unknown seek type");
514 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000515 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000516 if (where > self->size)
517 goto onoutofrange;
518 self->pos = where;
519 Py_INCREF (Py_None);
520 return (Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000521 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000522
Tim Peters5ebfd362001-11-13 23:11:19 +0000523 onoutofrange:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000524 PyErr_SetString (PyExc_ValueError, "seek out of range");
525 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000526}
527
528static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000529mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000530{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000531 unsigned long dest, src, count;
532 CHECK_VALID(NULL);
Tim Peters5ebfd362001-11-13 23:11:19 +0000533 if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count) ||
534 !is_writeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000535 return NULL;
536 } else {
537 /* bounds check the values */
538 if (/* end of source after end of data?? */
539 ((src+count) > self->size)
540 /* dest will fit? */
541 || (dest+count > self->size)) {
542 PyErr_SetString (PyExc_ValueError,
543 "source or destination out of range");
544 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000545 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000546 memmove (self->data+dest, self->data+src, count);
547 Py_INCREF (Py_None);
548 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000549 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000550 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000551}
552
553static struct PyMethodDef mmap_object_methods[] = {
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000554 {"close", (PyCFunction) mmap_close_method, METH_VARARGS},
555 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
556 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
557 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
558 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
559 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_VARARGS},
560 {"readline", (PyCFunction) mmap_read_line_method, METH_VARARGS},
561 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
562 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
563 {"size", (PyCFunction) mmap_size_method, METH_VARARGS},
564 {"tell", (PyCFunction) mmap_tell_method, METH_VARARGS},
565 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
566 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000567 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000568};
569
570/* Functions for treating an mmap'ed file as a buffer */
571
572static int
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000573mmap_buffer_getreadbuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000574{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000575 CHECK_VALID(-1);
576 if ( index != 0 ) {
577 PyErr_SetString(PyExc_SystemError,
578 "Accessing non-existent mmap segment");
579 return -1;
580 }
581 *ptr = self->data;
582 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000583}
584
585static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000586mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000587{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000588 CHECK_VALID(-1);
589 if ( index != 0 ) {
590 PyErr_SetString(PyExc_SystemError,
591 "Accessing non-existent mmap segment");
592 return -1;
593 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000594 if (!is_writeable(self))
595 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000596 *ptr = self->data;
597 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000598}
599
600static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000601mmap_buffer_getsegcount(mmap_object *self, int *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000602{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000603 CHECK_VALID(-1);
604 if (lenp)
605 *lenp = self->size;
606 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000607}
608
609static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000610mmap_buffer_getcharbuffer(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000611{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000612 if ( index != 0 ) {
613 PyErr_SetString(PyExc_SystemError,
614 "accessing non-existent buffer segment");
615 return -1;
616 }
617 *ptr = (const char *)self->data;
618 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000619}
620
621static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000622mmap_object_getattr(mmap_object *self, char *name)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000623{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000624 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000625}
626
627static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000628mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000629{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000630 CHECK_VALID(-1);
631 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000632}
633
634static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000635mmap_item(mmap_object *self, int i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000636{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000637 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000638 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000639 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
640 return NULL;
641 }
642 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000643}
644
645static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000646mmap_slice(mmap_object *self, int ilow, int ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000647{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000648 CHECK_VALID(NULL);
649 if (ilow < 0)
650 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000651 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000652 ilow = self->size;
653 if (ihigh < 0)
654 ihigh = 0;
655 if (ihigh < ilow)
656 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000657 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000658 ihigh = self->size;
659
660 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000661}
662
663static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000664mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000665{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000666 CHECK_VALID(NULL);
667 PyErr_SetString(PyExc_SystemError,
668 "mmaps don't support concatenation");
669 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000670}
671
672static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000673mmap_repeat(mmap_object *self, int n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000674{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000675 CHECK_VALID(NULL);
676 PyErr_SetString(PyExc_SystemError,
677 "mmaps don't support repeat operation");
678 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000679}
680
681static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000682mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000683{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000684 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000685
Guido van Rossum09fdf072000-03-31 01:17:07 +0000686 CHECK_VALID(-1);
687 if (ilow < 0)
688 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000689 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000690 ilow = self->size;
691 if (ihigh < 0)
692 ihigh = 0;
693 if (ihigh < ilow)
694 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000695 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000696 ihigh = self->size;
697
Thomas Wouters1baac722001-07-16 15:47:36 +0000698 if (v == NULL) {
699 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000700 "mmap object doesn't support slice deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000701 return -1;
702 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000703 if (! (PyString_Check(v)) ) {
704 PyErr_SetString(PyExc_IndexError,
705 "mmap slice assignment must be a string");
706 return -1;
707 }
708 if ( PyString_Size(v) != (ihigh - ilow) ) {
709 PyErr_SetString(PyExc_IndexError,
710 "mmap slice assignment is wrong size");
711 return -1;
712 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000713 if (!is_writeable(self))
714 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000715 buf = PyString_AsString(v);
716 memcpy(self->data + ilow, buf, ihigh-ilow);
717 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000718}
719
720static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000721mmap_ass_item(mmap_object *self, int i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000722{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000723 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000724
Guido van Rossum09fdf072000-03-31 01:17:07 +0000725 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000726 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000727 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
728 return -1;
729 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000730 if (v == NULL) {
731 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000732 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000733 return -1;
734 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000735 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
736 PyErr_SetString(PyExc_IndexError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000737 "mmap assignment must be single-character string");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000738 return -1;
739 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000740 if (!is_writeable(self))
741 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000742 buf = PyString_AsString(v);
743 self->data[i] = buf[0];
744 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000745}
746
747static PySequenceMethods mmap_as_sequence = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000748 (inquiry)mmap_length, /*sq_length*/
749 (binaryfunc)mmap_concat, /*sq_concat*/
750 (intargfunc)mmap_repeat, /*sq_repeat*/
751 (intargfunc)mmap_item, /*sq_item*/
752 (intintargfunc)mmap_slice, /*sq_slice*/
753 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
754 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000755};
756
757static PyBufferProcs mmap_as_buffer = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000758 (getreadbufferproc)mmap_buffer_getreadbuf,
759 (getwritebufferproc)mmap_buffer_getwritebuf,
760 (getsegcountproc)mmap_buffer_getsegcount,
761 (getcharbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000762};
763
764static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000765 PyObject_HEAD_INIT(0) /* patched in module init */
766 0, /* ob_size */
Guido van Rossum14648392001-12-08 18:02:58 +0000767 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000768 sizeof(mmap_object), /* tp_size */
769 0, /* tp_itemsize */
770 /* methods */
771 (destructor) mmap_object_dealloc, /* tp_dealloc */
772 0, /* tp_print */
773 (getattrfunc) mmap_object_getattr, /* tp_getattr */
774 0, /* tp_setattr */
775 0, /* tp_compare */
776 0, /* tp_repr */
777 0, /* tp_as_number */
778 &mmap_as_sequence, /*tp_as_sequence*/
779 0, /*tp_as_mapping*/
780 0, /*tp_hash*/
781 0, /*tp_call*/
782 0, /*tp_str*/
783 0, /*tp_getattro*/
784 0, /*tp_setattro*/
785 &mmap_as_buffer, /*tp_as_buffer*/
786 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
787 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000788};
789
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000790
791/* extract the map size from the given PyObject
792
793 The map size is restricted to [0, INT_MAX] because this is the current
794 Python limitation on object sizes. Although the mmap object *could* handle
795 a larger map size, there is no point because all the useful operations
796 (len(), slicing(), sequence indexing) are limited by a C int.
797
Thomas Wouters7e474022000-07-16 12:04:32 +0000798 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000799 success, the map size is returned. */
800static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000801_GetMapSize(PyObject *o)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000802{
803 if (PyInt_Check(o)) {
804 long i = PyInt_AsLong(o);
805 if (PyErr_Occurred())
806 return -1;
807 if (i < 0)
808 goto onnegoverflow;
809 if (i > INT_MAX)
810 goto onposoverflow;
811 return (int)i;
812 }
813 else if (PyLong_Check(o)) {
814 long i = PyLong_AsLong(o);
815 if (PyErr_Occurred()) {
816 /* yes negative overflow is mistaken for positive overflow
817 but not worth the trouble to check sign of 'i' */
818 if (PyErr_ExceptionMatches(PyExc_OverflowError))
819 goto onposoverflow;
820 else
821 return -1;
822 }
823 if (i < 0)
824 goto onnegoverflow;
825 if (i > INT_MAX)
826 goto onposoverflow;
827 return (int)i;
828 }
829 else {
830 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000831 "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000832 return -1;
833 }
834
Tim Peters5ebfd362001-11-13 23:11:19 +0000835 onnegoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000836 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000837 "memory mapped size must be positive");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000838 return -1;
839
Tim Peters5ebfd362001-11-13 23:11:19 +0000840 onposoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000841 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000842 "memory mapped size is too large (limited by C int)");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000843 return -1;
844}
845
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000846#ifdef UNIX
847static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000848new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000849{
Neal Norwitzb5673922002-09-05 21:48:07 +0000850#ifdef HAVE_FSTAT
851 struct stat st;
852#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000853 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000854 PyObject *map_size_obj = NULL;
855 int map_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000856 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Tim Peters5ebfd362001-11-13 23:11:19 +0000857 access_mode access = ACCESS_DEFAULT;
858 char *keywords[] = {"fileno", "length",
859 "flags", "prot",
860 "access", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000861
Tim Peters5ebfd362001-11-13 23:11:19 +0000862 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii", keywords,
863 &fd, &map_size_obj, &flags, &prot, &access))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000864 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000865 map_size = _GetMapSize(map_size_obj);
866 if (map_size < 0)
867 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000868
869 if ((access != ACCESS_DEFAULT) &&
870 ((flags != MAP_SHARED) || ( prot != (PROT_WRITE | PROT_READ))))
871 return PyErr_Format(PyExc_ValueError,
872 "mmap can't specify both access and flags, prot.");
873 switch(access) {
874 case ACCESS_READ:
875 flags = MAP_SHARED;
876 prot = PROT_READ;
877 break;
878 case ACCESS_WRITE:
879 flags = MAP_SHARED;
880 prot = PROT_READ | PROT_WRITE;
881 break;
882 case ACCESS_COPY:
883 flags = MAP_PRIVATE;
884 prot = PROT_READ | PROT_WRITE;
885 break;
886 case ACCESS_DEFAULT:
887 /* use the specified or default values of flags and prot */
888 break;
889 default:
890 return PyErr_Format(PyExc_ValueError,
891 "mmap invalid access parameter.");
892 }
Neal Norwitzb5673922002-09-05 21:48:07 +0000893
894#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +0000895# ifdef __VMS
896 /* on OpenVMS we must ensure that all bytes are written to the file */
897 fsync(fd);
898# endif
Andrew M. Kuchlinga3016672003-07-15 12:37:46 +0000899 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
900 (size_t)map_size > st.st_size) {
Neal Norwitzb5673922002-09-05 21:48:07 +0000901 PyErr_SetString(PyExc_ValueError,
902 "mmap length is greater than file size");
903 return NULL;
904 }
905#endif
Guido van Rossumb18618d2000-05-03 23:44:39 +0000906 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000907 if (m_obj == NULL) {return NULL;}
908 m_obj->size = (size_t) map_size;
909 m_obj->pos = (size_t) 0;
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000910 m_obj->fd = fd;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000911 m_obj->data = mmap(NULL, map_size,
912 prot, flags,
913 fd, 0);
Tim Peters5ebfd362001-11-13 23:11:19 +0000914 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +0000915 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000916 Py_DECREF(m_obj);
917 PyErr_SetFromErrno(mmap_module_error);
918 return NULL;
919 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000920 m_obj->access = access;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000921 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000922}
923#endif /* UNIX */
924
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000925#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000926static PyObject *
Tim Peters5ebfd362001-11-13 23:11:19 +0000927new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000928{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000929 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000930 PyObject *map_size_obj = NULL;
931 int map_size;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000932 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +0000933 DWORD dwErr = 0;
934 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +0000935 HANDLE fh = 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000936 access_mode access = ACCESS_DEFAULT;
937 DWORD flProtect, dwDesiredAccess;
938 char *keywords[] = { "fileno", "length",
939 "tagname",
940 "access", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000941
Tim Peters5ebfd362001-11-13 23:11:19 +0000942 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|zi", keywords,
943 &fileno, &map_size_obj,
944 &tagname, &access)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000945 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000946 }
947
948 switch(access) {
949 case ACCESS_READ:
950 flProtect = PAGE_READONLY;
951 dwDesiredAccess = FILE_MAP_READ;
952 break;
953 case ACCESS_DEFAULT: case ACCESS_WRITE:
954 flProtect = PAGE_READWRITE;
955 dwDesiredAccess = FILE_MAP_WRITE;
956 break;
957 case ACCESS_COPY:
958 flProtect = PAGE_WRITECOPY;
959 dwDesiredAccess = FILE_MAP_COPY;
960 break;
961 default:
962 return PyErr_Format(PyExc_ValueError,
963 "mmap invalid access parameter.");
964 }
965
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000966 map_size = _GetMapSize(map_size_obj);
967 if (map_size < 0)
968 return NULL;
969
Guido van Rossum09fdf072000-03-31 01:17:07 +0000970 /* if an actual filename has been specified */
971 if (fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +0000972 fh = (HANDLE)_get_osfhandle(fileno);
973 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +0000974 PyErr_SetFromErrno(mmap_module_error);
975 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000976 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +0000977 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +0000978 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000979 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000980
Guido van Rossumb18618d2000-05-03 23:44:39 +0000981 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Mark Hammond2cbed002000-07-30 02:22:43 +0000982 if (m_obj==NULL)
983 return NULL;
984 /* Set every field to an invalid marker, so we can safely
985 destruct the object in the face of failure */
986 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +0000987 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +0000988 m_obj->map_handle = INVALID_HANDLE_VALUE;
989 m_obj->tagname = NULL;
990
Guido van Rossum09fdf072000-03-31 01:17:07 +0000991 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +0000992 /* It is necessary to duplicate the handle, so the
993 Python code can close it on us */
994 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +0000995 GetCurrentProcess(), /* source process handle */
996 fh, /* handle to be duplicated */
997 GetCurrentProcess(), /* target proc handle */
998 (LPHANDLE)&m_obj->file_handle, /* result */
999 0, /* access - ignored due to options value */
1000 FALSE, /* inherited by child processes? */
1001 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001002 dwErr = GetLastError();
1003 Py_DECREF(m_obj);
1004 PyErr_SetFromWindowsErr(dwErr);
1005 return NULL;
1006 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001007 if (!map_size) {
Mark Hammond071864a2000-07-30 02:46:26 +00001008 m_obj->size = GetFileSize (fh, NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001009 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001010 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001011 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001012 }
1013 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001014 m_obj->size = map_size;
1015 }
1016
1017 /* set the initial position */
1018 m_obj->pos = (size_t) 0;
1019
Mark Hammond2cbed002000-07-30 02:22:43 +00001020 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001021 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001022 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1023 if (m_obj->tagname == NULL) {
1024 PyErr_NoMemory();
1025 Py_DECREF(m_obj);
1026 return NULL;
1027 }
1028 strcpy(m_obj->tagname, tagname);
1029 }
1030 else
1031 m_obj->tagname = NULL;
1032
Tim Peters5ebfd362001-11-13 23:11:19 +00001033 m_obj->access = access;
Mark Hammond071864a2000-07-30 02:46:26 +00001034 m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001035 NULL,
Tim Peters5ebfd362001-11-13 23:11:19 +00001036 flProtect,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001037 0,
1038 m_obj->size,
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001039 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001040 if (m_obj->map_handle != NULL) {
1041 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
Tim Peters5ebfd362001-11-13 23:11:19 +00001042 dwDesiredAccess,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001043 0,
1044 0,
1045 0);
1046 if (m_obj->data != NULL) {
1047 return ((PyObject *) m_obj);
1048 } else {
Tim Peters5ebfd362001-11-13 23:11:19 +00001049 dwErr = GetLastError();
Guido van Rossum09fdf072000-03-31 01:17:07 +00001050 }
1051 } else {
1052 dwErr = GetLastError();
1053 }
Mark Hammond2cbed002000-07-30 02:22:43 +00001054 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001055 PyErr_SetFromWindowsErr(dwErr);
1056 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001057}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001058#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001059
1060/* List of functions exported by this module */
1061static struct PyMethodDef mmap_functions[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001062 {"mmap", (PyCFunction) new_mmap_object,
1063 METH_VARARGS|METH_KEYWORDS},
1064 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001065};
1066
Mark Hammond62b1ab12002-07-23 06:31:15 +00001067PyMODINIT_FUNC
Tim Peters5ebfd362001-11-13 23:11:19 +00001068 initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001069{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001070 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001071
1072 /* Patch the object type */
1073 mmap_object_type.ob_type = &PyType_Type;
1074
Guido van Rossum09fdf072000-03-31 01:17:07 +00001075 module = Py_InitModule ("mmap", mmap_functions);
1076 dict = PyModule_GetDict (module);
1077 mmap_module_error = PyExc_EnvironmentError;
1078 Py_INCREF(mmap_module_error);
1079 PyDict_SetItemString (dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001080#ifdef PROT_EXEC
Guido van Rossum09fdf072000-03-31 01:17:07 +00001081 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001082#endif
1083#ifdef PROT_READ
Guido van Rossum09fdf072000-03-31 01:17:07 +00001084 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001085#endif
1086#ifdef PROT_WRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001087 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001088#endif
1089
1090#ifdef MAP_SHARED
Guido van Rossum09fdf072000-03-31 01:17:07 +00001091 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001092#endif
1093#ifdef MAP_PRIVATE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001094 PyDict_SetItemString (dict, "MAP_PRIVATE",
1095 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001096#endif
1097#ifdef MAP_DENYWRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001098 PyDict_SetItemString (dict, "MAP_DENYWRITE",
1099 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001100#endif
1101#ifdef MAP_EXECUTABLE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001102 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
1103 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001104#endif
1105#ifdef MAP_ANON
Guido van Rossum09fdf072000-03-31 01:17:07 +00001106 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
1107 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
1108 PyInt_FromLong(MAP_ANON) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001109#endif
1110
Guido van Rossum09fdf072000-03-31 01:17:07 +00001111 PyDict_SetItemString (dict, "PAGESIZE",
Fred Drake145f96e2000-10-01 17:50:46 +00001112 PyInt_FromLong( (long)my_getpagesize() ) );
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001113
Tim Peters5ebfd362001-11-13 23:11:19 +00001114 PyDict_SetItemString (dict, "ACCESS_READ",
1115 PyInt_FromLong(ACCESS_READ));
1116 PyDict_SetItemString (dict, "ACCESS_WRITE",
1117 PyInt_FromLong(ACCESS_WRITE));
1118 PyDict_SetItemString (dict, "ACCESS_COPY",
1119 PyInt_FromLong(ACCESS_COPY));
1120}