blob: 51487a744647a9f0e04f23dceba9004350461482 [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
Neal Norwitz6eac2002005-11-02 05:36:37 +0000102 if (m_obj->fd >= 0)
103 (void) close(m_obj->fd);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000104 if (m_obj->data!=NULL) {
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000105 msync(m_obj->data, m_obj->size, MS_SYNC);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000106 munmap(m_obj->data, m_obj->size);
107 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000108#endif /* UNIX */
109
Guido van Rossumb18618d2000-05-03 23:44:39 +0000110 PyObject_Del(m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000111}
112
113static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000114mmap_close_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000115{
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000116 if (!PyArg_ParseTuple(args, ":close"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000117 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000118#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000119 /* For each resource we maintain, we need to check
120 the value is valid, and if so, free the resource
121 and set the member value to an invalid value so
122 the dealloc does not attempt to resource clearing
123 again.
124 TODO - should we check for errors in the close operations???
125 */
126 if (self->data != NULL) {
127 UnmapViewOfFile (self->data);
128 self->data = NULL;
129 }
130 if (self->map_handle != INVALID_HANDLE_VALUE) {
131 CloseHandle (self->map_handle);
132 self->map_handle = INVALID_HANDLE_VALUE;
133 }
134 if (self->file_handle != INVALID_HANDLE_VALUE) {
135 CloseHandle (self->file_handle);
136 self->file_handle = INVALID_HANDLE_VALUE;
137 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000138#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000139
140#ifdef UNIX
Neal Norwitz6eac2002005-11-02 05:36:37 +0000141 (void) close(self->fd);
142 self->fd = -1;
Neal Norwitze604c022003-01-10 20:52:16 +0000143 if (self->data != NULL) {
144 munmap(self->data, self->size);
145 self->data = NULL;
146 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000147#endif
148
Guido van Rossum09fdf072000-03-31 01:17:07 +0000149 Py_INCREF (Py_None);
150 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000151}
152
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000153#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +0000154#define CHECK_VALID(err) \
155do { \
Guido van Rossum69c2b882003-04-09 19:31:02 +0000156 if (self->map_handle == INVALID_HANDLE_VALUE) { \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000157 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
158 return err; \
159 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000160} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000161#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000162
163#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000164#define CHECK_VALID(err) \
165do { \
166 if (self->data == NULL) { \
167 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
168 return err; \
169 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000170} while (0)
171#endif /* UNIX */
172
173static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000174mmap_read_byte_method(mmap_object *self,
175 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000176{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000177 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000178 if (!PyArg_ParseTuple(args, ":read_byte"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000179 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000180 if (self->pos < self->size) {
Tim Petersd6283b82001-05-09 18:48:26 +0000181 char value = self->data[self->pos];
Guido van Rossum09fdf072000-03-31 01:17:07 +0000182 self->pos += 1;
Tim Petersd6283b82001-05-09 18:48:26 +0000183 return Py_BuildValue("c", value);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000184 } else {
185 PyErr_SetString (PyExc_ValueError, "read byte out of range");
186 return NULL;
187 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000188}
189
190static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000191mmap_read_line_method(mmap_object *self,
Tim Peters5ebfd362001-11-13 23:11:19 +0000192 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000193{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000194 char *start = self->data+self->pos;
195 char *eof = self->data+self->size;
196 char *eol;
197 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000198
Guido van Rossum09fdf072000-03-31 01:17:07 +0000199 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000200 if (!PyArg_ParseTuple(args, ":readline"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000201 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000202
Fred Drake56a87a02000-04-04 18:17:35 +0000203 eol = memchr(start, '\n', self->size - self->pos);
204 if (!eol)
205 eol = eof;
206 else
207 ++eol; /* we're interested in the position after the
208 newline. */
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000209 result = PyString_FromStringAndSize(start, (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000210 self->pos += (eol - start);
211 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000212}
213
214static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000215mmap_read_method(mmap_object *self,
216 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000217{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000218 long num_bytes;
219 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000220
Guido van Rossum09fdf072000-03-31 01:17:07 +0000221 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000222 if (!PyArg_ParseTuple(args, "l:read", &num_bytes))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000223 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000224
Guido van Rossum09fdf072000-03-31 01:17:07 +0000225 /* silently 'adjust' out-of-range requests */
226 if ((self->pos + num_bytes) > self->size) {
227 num_bytes -= (self->pos+num_bytes) - self->size;
228 }
229 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
230 self->pos += num_bytes;
231 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000232}
233
234static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000235mmap_find_method(mmap_object *self,
236 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000237{
Tim Petersd401edd2001-05-14 23:19:12 +0000238 long start = self->pos;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000239 char *needle;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000240 int len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000241
Guido van Rossum09fdf072000-03-31 01:17:07 +0000242 CHECK_VALID(NULL);
Tim Petersd401edd2001-05-14 23:19:12 +0000243 if (!PyArg_ParseTuple (args, "s#|l:find", &needle, &len, &start)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000244 return NULL;
245 } else {
Greg Stein834f4dd2001-05-14 09:32:26 +0000246 char *p;
247 char *e = self->data + self->size;
248
249 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000250 start += self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000251 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000252 start = 0;
Tim Petersd401edd2001-05-14 23:19:12 +0000253 else if ((size_t)start > self->size)
Tim Peters5ebfd362001-11-13 23:11:19 +0000254 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000255
Tim Petersc9ffa062002-03-08 05:43:32 +0000256 for (p = self->data + start; p + len <= e; ++p) {
257 int i;
258 for (i = 0; i < len && needle[i] == p[i]; ++i)
259 /* nothing */;
260 if (i == len) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000261 return Py_BuildValue (
Tim Petersd401edd2001-05-14 23:19:12 +0000262 "l",
263 (long) (p - self->data));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000264 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000265 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000266 return Py_BuildValue ("l", (long) -1);
267 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000268}
269
Tim Peters5ebfd362001-11-13 23:11:19 +0000270static int
271is_writeable(mmap_object *self)
272{
273 if (self->access != ACCESS_READ)
274 return 1;
275 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
276 return 0;
277}
278
279static int
280is_resizeable(mmap_object *self)
281{
282 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
283 return 1;
284 PyErr_Format(PyExc_TypeError,
285 "mmap can't resize a readonly or copy-on-write memory map.");
286 return 0;
287}
288
289
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000290static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000291mmap_write_method(mmap_object *self,
292 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000293{
Neal Norwitz4d933fe2003-02-07 19:44:56 +0000294 int length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000295 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000296
Guido van Rossum09fdf072000-03-31 01:17:07 +0000297 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000298 if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000299 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000300
Tim Peters5ebfd362001-11-13 23:11:19 +0000301 if (!is_writeable(self))
302 return NULL;
303
Guido van Rossum09fdf072000-03-31 01:17:07 +0000304 if ((self->pos + length) > self->size) {
305 PyErr_SetString (PyExc_ValueError, "data out of range");
306 return NULL;
307 }
308 memcpy (self->data+self->pos, data, length);
309 self->pos = self->pos+length;
310 Py_INCREF (Py_None);
311 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000312}
313
314static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000315mmap_write_byte_method(mmap_object *self,
316 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000317{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000318 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000319
Guido van Rossum09fdf072000-03-31 01:17:07 +0000320 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000321 if (!PyArg_ParseTuple (args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000322 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000323
Tim Peters5ebfd362001-11-13 23:11:19 +0000324 if (!is_writeable(self))
325 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000326 *(self->data+self->pos) = value;
327 self->pos += 1;
328 Py_INCREF (Py_None);
329 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000330}
Tim Peters5ebfd362001-11-13 23:11:19 +0000331
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000332static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000333mmap_size_method(mmap_object *self,
334 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000335{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000336 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000337 if (!PyArg_ParseTuple(args, ":size"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000338 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000339
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000340#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000341 if (self->file_handle != INVALID_HANDLE_VALUE) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000342 return (Py_BuildValue (
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000343 "l", (long)
Mark Hammond071864a2000-07-30 02:46:26 +0000344 GetFileSize (self->file_handle, NULL)));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000345 } else {
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000346 return (Py_BuildValue ("l", (long) self->size) );
Guido van Rossum09fdf072000-03-31 01:17:07 +0000347 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000348#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000349
350#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000351 {
352 struct stat buf;
353 if (-1 == fstat(self->fd, &buf)) {
354 PyErr_SetFromErrno(mmap_module_error);
355 return NULL;
356 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000357 return (Py_BuildValue ("l", (long) buf.st_size) );
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000358 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000359#endif /* UNIX */
360}
361
362/* This assumes that you want the entire file mapped,
363 / and when recreating the map will make the new file
364 / have the new size
365 /
366 / Is this really necessary? This could easily be done
367 / from python by just closing and re-opening with the
368 / new size?
369 */
370
371static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000372mmap_resize_method(mmap_object *self,
373 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000374{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000375 unsigned long new_size;
376 CHECK_VALID(NULL);
Tim Peters5ebfd362001-11-13 23:11:19 +0000377 if (!PyArg_ParseTuple (args, "l:resize", &new_size) ||
378 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000379 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000380#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +0000381 } else {
382 DWORD dwErrCode = 0;
383 /* First, unmap the file view */
384 UnmapViewOfFile (self->data);
385 /* Close the mapping object */
Mark Hammond071864a2000-07-30 02:46:26 +0000386 CloseHandle (self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000387 /* Move to the desired EOF position */
Mark Hammond071864a2000-07-30 02:46:26 +0000388 SetFilePointer (self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000389 new_size, NULL, FILE_BEGIN);
390 /* Change the size of the file */
Mark Hammond071864a2000-07-30 02:46:26 +0000391 SetEndOfFile (self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000392 /* Create another mapping object and remap the file view */
393 self->map_handle = CreateFileMapping (
Mark Hammond071864a2000-07-30 02:46:26 +0000394 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000395 NULL,
396 PAGE_READWRITE,
397 0,
398 new_size,
399 self->tagname);
400 if (self->map_handle != NULL) {
401 self->data = (char *) MapViewOfFile (self->map_handle,
402 FILE_MAP_WRITE,
403 0,
404 0,
405 0);
406 if (self->data != NULL) {
407 self->size = new_size;
408 Py_INCREF (Py_None);
409 return Py_None;
410 } else {
411 dwErrCode = GetLastError();
412 }
413 } else {
414 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000415 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000416 PyErr_SetFromWindowsErr(dwErrCode);
417 return (NULL);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000418#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000419
420#ifdef UNIX
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000421#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000422 } else {
423 PyErr_SetString(PyExc_SystemError,
424 "mmap: resizing not available--no mremap()");
425 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000426#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000427 } else {
Armin Rigo335ffe82005-09-20 19:04:02 +0000428 void *newmap;
429
Georg Brandl38387b82005-08-24 07:17:40 +0000430 if (ftruncate(self->fd, new_size) == -1) {
431 PyErr_SetFromErrno(mmap_module_error);
432 return NULL;
433 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000434
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000435#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000436 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000437#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000438 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000439#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000440 if (newmap == (void *)-1)
441 {
442 PyErr_SetFromErrno(mmap_module_error);
443 return NULL;
444 }
445 self->data = newmap;
446 self->size = new_size;
447 Py_INCREF(Py_None);
448 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000449#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000450#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000451 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000452}
453
454static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000455mmap_tell_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000456{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000457 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000458 if (!PyArg_ParseTuple(args, ":tell"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000459 return NULL;
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000460 return (Py_BuildValue ("l", (long) self->pos) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000461}
462
463static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000464mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000465{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000466 size_t offset = 0;
467 size_t size = self->size;
468 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000469 if (!PyArg_ParseTuple (args, "|ll:flush", &offset, &size)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000470 return NULL;
471 } else if ((offset + size) > self->size) {
472 PyErr_SetString (PyExc_ValueError,
473 "flush values out of range");
474 return NULL;
475 } else {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000476#ifdef MS_WINDOWS
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000477 return (Py_BuildValue("l", (long)
478 FlushViewOfFile(self->data+offset, size)));
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000479#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000480#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000481 /* XXX semantics of return value? */
482 /* XXX flags for msync? */
483 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000484 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000485 {
486 PyErr_SetFromErrno(mmap_module_error);
487 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000488 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000489 return Py_BuildValue ("l", (long) 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000490#endif /* UNIX */
491 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000492}
493
494static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000495mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000496{
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000497 int dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000498 int how=0;
499 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000500 if (!PyArg_ParseTuple (args, "i|i:seek", &dist, &how)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000501 return(NULL);
502 } else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000503 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000504 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000505 case 0: /* relative to start */
506 if (dist < 0)
507 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000508 where = dist;
509 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000510 case 1: /* relative to current position */
511 if ((int)self->pos + dist < 0)
512 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000513 where = self->pos + dist;
514 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000515 case 2: /* relative to end */
516 if ((int)self->size + dist < 0)
517 goto onoutofrange;
518 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000519 break;
520 default:
521 PyErr_SetString (PyExc_ValueError,
522 "unknown seek type");
523 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000524 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000525 if (where > self->size)
526 goto onoutofrange;
527 self->pos = where;
528 Py_INCREF (Py_None);
529 return (Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000530 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000531
Tim Peters5ebfd362001-11-13 23:11:19 +0000532 onoutofrange:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000533 PyErr_SetString (PyExc_ValueError, "seek out of range");
534 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000535}
536
537static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000538mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000539{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000540 unsigned long dest, src, count;
541 CHECK_VALID(NULL);
Tim Peters5ebfd362001-11-13 23:11:19 +0000542 if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count) ||
543 !is_writeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000544 return NULL;
545 } else {
546 /* bounds check the values */
547 if (/* end of source after end of data?? */
548 ((src+count) > self->size)
549 /* dest will fit? */
550 || (dest+count > self->size)) {
551 PyErr_SetString (PyExc_ValueError,
552 "source or destination out of range");
553 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000554 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000555 memmove (self->data+dest, self->data+src, count);
556 Py_INCREF (Py_None);
557 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000558 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000559 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000560}
561
562static struct PyMethodDef mmap_object_methods[] = {
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000563 {"close", (PyCFunction) mmap_close_method, METH_VARARGS},
564 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
565 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
566 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
567 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
568 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_VARARGS},
569 {"readline", (PyCFunction) mmap_read_line_method, METH_VARARGS},
570 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
571 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
572 {"size", (PyCFunction) mmap_size_method, METH_VARARGS},
573 {"tell", (PyCFunction) mmap_tell_method, METH_VARARGS},
574 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
575 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000576 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000577};
578
579/* Functions for treating an mmap'ed file as a buffer */
580
581static int
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000582mmap_buffer_getreadbuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000583{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000584 CHECK_VALID(-1);
585 if ( index != 0 ) {
586 PyErr_SetString(PyExc_SystemError,
587 "Accessing non-existent mmap segment");
588 return -1;
589 }
590 *ptr = self->data;
591 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000592}
593
594static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000595mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000596{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000597 CHECK_VALID(-1);
598 if ( index != 0 ) {
599 PyErr_SetString(PyExc_SystemError,
600 "Accessing non-existent mmap segment");
601 return -1;
602 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000603 if (!is_writeable(self))
604 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000605 *ptr = self->data;
606 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000607}
608
609static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000610mmap_buffer_getsegcount(mmap_object *self, int *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000611{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000612 CHECK_VALID(-1);
613 if (lenp)
614 *lenp = self->size;
615 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000616}
617
618static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000619mmap_buffer_getcharbuffer(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000620{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000621 if ( index != 0 ) {
622 PyErr_SetString(PyExc_SystemError,
623 "accessing non-existent buffer segment");
624 return -1;
625 }
626 *ptr = (const char *)self->data;
627 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000628}
629
630static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000631mmap_object_getattr(mmap_object *self, char *name)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000632{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000633 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000634}
635
636static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000637mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000638{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000639 CHECK_VALID(-1);
640 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000641}
642
643static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000644mmap_item(mmap_object *self, int i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000645{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000646 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000647 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000648 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
649 return NULL;
650 }
651 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000652}
653
654static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000655mmap_slice(mmap_object *self, int ilow, int ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000656{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000657 CHECK_VALID(NULL);
658 if (ilow < 0)
659 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000660 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000661 ilow = self->size;
662 if (ihigh < 0)
663 ihigh = 0;
664 if (ihigh < ilow)
665 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000666 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000667 ihigh = self->size;
668
669 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000670}
671
672static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000673mmap_concat(mmap_object *self, PyObject *bb)
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 concatenation");
678 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000679}
680
681static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000682mmap_repeat(mmap_object *self, int n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000683{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000684 CHECK_VALID(NULL);
685 PyErr_SetString(PyExc_SystemError,
686 "mmaps don't support repeat operation");
687 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000688}
689
690static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000691mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000692{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000693 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000694
Guido van Rossum09fdf072000-03-31 01:17:07 +0000695 CHECK_VALID(-1);
696 if (ilow < 0)
697 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000698 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000699 ilow = self->size;
700 if (ihigh < 0)
701 ihigh = 0;
702 if (ihigh < ilow)
703 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000704 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000705 ihigh = self->size;
706
Thomas Wouters1baac722001-07-16 15:47:36 +0000707 if (v == NULL) {
708 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000709 "mmap object doesn't support slice deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000710 return -1;
711 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000712 if (! (PyString_Check(v)) ) {
713 PyErr_SetString(PyExc_IndexError,
714 "mmap slice assignment must be a string");
715 return -1;
716 }
717 if ( PyString_Size(v) != (ihigh - ilow) ) {
718 PyErr_SetString(PyExc_IndexError,
719 "mmap slice assignment is wrong size");
720 return -1;
721 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000722 if (!is_writeable(self))
723 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000724 buf = PyString_AsString(v);
725 memcpy(self->data + ilow, buf, ihigh-ilow);
726 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000727}
728
729static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000730mmap_ass_item(mmap_object *self, int i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000731{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000732 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000733
Guido van Rossum09fdf072000-03-31 01:17:07 +0000734 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000735 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000736 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
737 return -1;
738 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000739 if (v == NULL) {
740 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000741 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000742 return -1;
743 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000744 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
745 PyErr_SetString(PyExc_IndexError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000746 "mmap assignment must be single-character string");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000747 return -1;
748 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000749 if (!is_writeable(self))
750 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000751 buf = PyString_AsString(v);
752 self->data[i] = buf[0];
753 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000754}
755
756static PySequenceMethods mmap_as_sequence = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000757 (inquiry)mmap_length, /*sq_length*/
758 (binaryfunc)mmap_concat, /*sq_concat*/
759 (intargfunc)mmap_repeat, /*sq_repeat*/
760 (intargfunc)mmap_item, /*sq_item*/
761 (intintargfunc)mmap_slice, /*sq_slice*/
762 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
763 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000764};
765
766static PyBufferProcs mmap_as_buffer = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000767 (getreadbufferproc)mmap_buffer_getreadbuf,
768 (getwritebufferproc)mmap_buffer_getwritebuf,
769 (getsegcountproc)mmap_buffer_getsegcount,
770 (getcharbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000771};
772
773static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000774 PyObject_HEAD_INIT(0) /* patched in module init */
775 0, /* ob_size */
Guido van Rossum14648392001-12-08 18:02:58 +0000776 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000777 sizeof(mmap_object), /* tp_size */
778 0, /* tp_itemsize */
779 /* methods */
780 (destructor) mmap_object_dealloc, /* tp_dealloc */
781 0, /* tp_print */
782 (getattrfunc) mmap_object_getattr, /* tp_getattr */
783 0, /* tp_setattr */
784 0, /* tp_compare */
785 0, /* tp_repr */
786 0, /* tp_as_number */
787 &mmap_as_sequence, /*tp_as_sequence*/
788 0, /*tp_as_mapping*/
789 0, /*tp_hash*/
790 0, /*tp_call*/
791 0, /*tp_str*/
792 0, /*tp_getattro*/
793 0, /*tp_setattro*/
794 &mmap_as_buffer, /*tp_as_buffer*/
795 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
796 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000797};
798
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000799
800/* extract the map size from the given PyObject
801
802 The map size is restricted to [0, INT_MAX] because this is the current
803 Python limitation on object sizes. Although the mmap object *could* handle
804 a larger map size, there is no point because all the useful operations
805 (len(), slicing(), sequence indexing) are limited by a C int.
806
Thomas Wouters7e474022000-07-16 12:04:32 +0000807 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000808 success, the map size is returned. */
809static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000810_GetMapSize(PyObject *o)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000811{
812 if (PyInt_Check(o)) {
813 long i = PyInt_AsLong(o);
814 if (PyErr_Occurred())
815 return -1;
816 if (i < 0)
817 goto onnegoverflow;
818 if (i > INT_MAX)
819 goto onposoverflow;
820 return (int)i;
821 }
822 else if (PyLong_Check(o)) {
823 long i = PyLong_AsLong(o);
824 if (PyErr_Occurred()) {
825 /* yes negative overflow is mistaken for positive overflow
826 but not worth the trouble to check sign of 'i' */
827 if (PyErr_ExceptionMatches(PyExc_OverflowError))
828 goto onposoverflow;
829 else
830 return -1;
831 }
832 if (i < 0)
833 goto onnegoverflow;
834 if (i > INT_MAX)
835 goto onposoverflow;
836 return (int)i;
837 }
838 else {
839 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000840 "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000841 return -1;
842 }
843
Tim Peters5ebfd362001-11-13 23:11:19 +0000844 onnegoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000845 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000846 "memory mapped size must be positive");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000847 return -1;
848
Tim Peters5ebfd362001-11-13 23:11:19 +0000849 onposoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000850 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000851 "memory mapped size is too large (limited by C int)");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000852 return -1;
853}
854
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000855#ifdef UNIX
856static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000857new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000858{
Neal Norwitzb5673922002-09-05 21:48:07 +0000859#ifdef HAVE_FSTAT
860 struct stat st;
861#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000862 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000863 PyObject *map_size_obj = NULL;
864 int map_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000865 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Tim Peters5ebfd362001-11-13 23:11:19 +0000866 access_mode access = ACCESS_DEFAULT;
867 char *keywords[] = {"fileno", "length",
868 "flags", "prot",
869 "access", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000870
Tim Peters5ebfd362001-11-13 23:11:19 +0000871 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii", keywords,
872 &fd, &map_size_obj, &flags, &prot, &access))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000873 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000874 map_size = _GetMapSize(map_size_obj);
875 if (map_size < 0)
876 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000877
878 if ((access != ACCESS_DEFAULT) &&
879 ((flags != MAP_SHARED) || ( prot != (PROT_WRITE | PROT_READ))))
880 return PyErr_Format(PyExc_ValueError,
881 "mmap can't specify both access and flags, prot.");
882 switch(access) {
883 case ACCESS_READ:
884 flags = MAP_SHARED;
885 prot = PROT_READ;
886 break;
887 case ACCESS_WRITE:
888 flags = MAP_SHARED;
889 prot = PROT_READ | PROT_WRITE;
890 break;
891 case ACCESS_COPY:
892 flags = MAP_PRIVATE;
893 prot = PROT_READ | PROT_WRITE;
894 break;
895 case ACCESS_DEFAULT:
896 /* use the specified or default values of flags and prot */
897 break;
898 default:
899 return PyErr_Format(PyExc_ValueError,
900 "mmap invalid access parameter.");
901 }
Neal Norwitzb5673922002-09-05 21:48:07 +0000902
903#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +0000904# ifdef __VMS
905 /* on OpenVMS we must ensure that all bytes are written to the file */
906 fsync(fd);
907# endif
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000908 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
909 if (map_size == 0) {
910 map_size = (int)st.st_size;
911 } else if ((size_t)map_size > st.st_size) {
912 PyErr_SetString(PyExc_ValueError,
913 "mmap length is greater than file size");
914 return NULL;
915 }
Neal Norwitzb5673922002-09-05 21:48:07 +0000916 }
917#endif
Guido van Rossumb18618d2000-05-03 23:44:39 +0000918 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000919 if (m_obj == NULL) {return NULL;}
920 m_obj->size = (size_t) map_size;
921 m_obj->pos = (size_t) 0;
Georg Brandl38387b82005-08-24 07:17:40 +0000922 m_obj->fd = dup(fd);
923 if (m_obj->fd == -1) {
924 Py_DECREF(m_obj);
925 PyErr_SetFromErrno(mmap_module_error);
926 return NULL;
927 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000928 m_obj->data = mmap(NULL, map_size,
929 prot, flags,
930 fd, 0);
Tim Peters5ebfd362001-11-13 23:11:19 +0000931 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +0000932 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000933 Py_DECREF(m_obj);
934 PyErr_SetFromErrno(mmap_module_error);
935 return NULL;
936 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000937 m_obj->access = access;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000938 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000939}
940#endif /* UNIX */
941
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000942#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000943static PyObject *
Tim Peters5ebfd362001-11-13 23:11:19 +0000944new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000945{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000946 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000947 PyObject *map_size_obj = NULL;
948 int map_size;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000949 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +0000950 DWORD dwErr = 0;
951 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +0000952 HANDLE fh = 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000953 access_mode access = ACCESS_DEFAULT;
954 DWORD flProtect, dwDesiredAccess;
955 char *keywords[] = { "fileno", "length",
956 "tagname",
957 "access", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000958
Tim Peters5ebfd362001-11-13 23:11:19 +0000959 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|zi", keywords,
960 &fileno, &map_size_obj,
961 &tagname, &access)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000962 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000963 }
964
965 switch(access) {
966 case ACCESS_READ:
967 flProtect = PAGE_READONLY;
968 dwDesiredAccess = FILE_MAP_READ;
969 break;
970 case ACCESS_DEFAULT: case ACCESS_WRITE:
971 flProtect = PAGE_READWRITE;
972 dwDesiredAccess = FILE_MAP_WRITE;
973 break;
974 case ACCESS_COPY:
975 flProtect = PAGE_WRITECOPY;
976 dwDesiredAccess = FILE_MAP_COPY;
977 break;
978 default:
979 return PyErr_Format(PyExc_ValueError,
980 "mmap invalid access parameter.");
981 }
982
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000983 map_size = _GetMapSize(map_size_obj);
984 if (map_size < 0)
985 return NULL;
986
Guido van Rossum09fdf072000-03-31 01:17:07 +0000987 /* if an actual filename has been specified */
988 if (fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +0000989 fh = (HANDLE)_get_osfhandle(fileno);
990 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +0000991 PyErr_SetFromErrno(mmap_module_error);
992 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000993 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +0000994 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +0000995 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000996 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000997
Guido van Rossumb18618d2000-05-03 23:44:39 +0000998 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Mark Hammond2cbed002000-07-30 02:22:43 +0000999 if (m_obj==NULL)
1000 return NULL;
1001 /* Set every field to an invalid marker, so we can safely
1002 destruct the object in the face of failure */
1003 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001004 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +00001005 m_obj->map_handle = INVALID_HANDLE_VALUE;
1006 m_obj->tagname = NULL;
1007
Guido van Rossum09fdf072000-03-31 01:17:07 +00001008 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001009 /* It is necessary to duplicate the handle, so the
1010 Python code can close it on us */
1011 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001012 GetCurrentProcess(), /* source process handle */
1013 fh, /* handle to be duplicated */
1014 GetCurrentProcess(), /* target proc handle */
1015 (LPHANDLE)&m_obj->file_handle, /* result */
1016 0, /* access - ignored due to options value */
1017 FALSE, /* inherited by child processes? */
1018 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001019 dwErr = GetLastError();
1020 Py_DECREF(m_obj);
1021 PyErr_SetFromWindowsErr(dwErr);
1022 return NULL;
1023 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001024 if (!map_size) {
Mark Hammond071864a2000-07-30 02:46:26 +00001025 m_obj->size = GetFileSize (fh, NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001026 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001027 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001028 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001029 }
1030 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001031 m_obj->size = map_size;
1032 }
1033
1034 /* set the initial position */
1035 m_obj->pos = (size_t) 0;
1036
Mark Hammond2cbed002000-07-30 02:22:43 +00001037 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001038 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001039 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1040 if (m_obj->tagname == NULL) {
1041 PyErr_NoMemory();
1042 Py_DECREF(m_obj);
1043 return NULL;
1044 }
1045 strcpy(m_obj->tagname, tagname);
1046 }
1047 else
1048 m_obj->tagname = NULL;
1049
Tim Peters5ebfd362001-11-13 23:11:19 +00001050 m_obj->access = access;
Mark Hammond071864a2000-07-30 02:46:26 +00001051 m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001052 NULL,
Tim Peters5ebfd362001-11-13 23:11:19 +00001053 flProtect,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001054 0,
1055 m_obj->size,
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001056 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001057 if (m_obj->map_handle != NULL) {
1058 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
Tim Peters5ebfd362001-11-13 23:11:19 +00001059 dwDesiredAccess,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001060 0,
1061 0,
1062 0);
1063 if (m_obj->data != NULL) {
1064 return ((PyObject *) m_obj);
1065 } else {
Tim Peters5ebfd362001-11-13 23:11:19 +00001066 dwErr = GetLastError();
Guido van Rossum09fdf072000-03-31 01:17:07 +00001067 }
1068 } else {
1069 dwErr = GetLastError();
1070 }
Mark Hammond2cbed002000-07-30 02:22:43 +00001071 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001072 PyErr_SetFromWindowsErr(dwErr);
1073 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001074}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001075#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001076
1077/* List of functions exported by this module */
1078static struct PyMethodDef mmap_functions[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001079 {"mmap", (PyCFunction) new_mmap_object,
1080 METH_VARARGS|METH_KEYWORDS},
1081 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001082};
1083
Mark Hammond62b1ab12002-07-23 06:31:15 +00001084PyMODINIT_FUNC
Tim Peters5ebfd362001-11-13 23:11:19 +00001085 initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001086{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001087 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001088
1089 /* Patch the object type */
1090 mmap_object_type.ob_type = &PyType_Type;
1091
Guido van Rossum09fdf072000-03-31 01:17:07 +00001092 module = Py_InitModule ("mmap", mmap_functions);
1093 dict = PyModule_GetDict (module);
1094 mmap_module_error = PyExc_EnvironmentError;
1095 Py_INCREF(mmap_module_error);
1096 PyDict_SetItemString (dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001097#ifdef PROT_EXEC
Guido van Rossum09fdf072000-03-31 01:17:07 +00001098 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001099#endif
1100#ifdef PROT_READ
Guido van Rossum09fdf072000-03-31 01:17:07 +00001101 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001102#endif
1103#ifdef PROT_WRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001104 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001105#endif
1106
1107#ifdef MAP_SHARED
Guido van Rossum09fdf072000-03-31 01:17:07 +00001108 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001109#endif
1110#ifdef MAP_PRIVATE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001111 PyDict_SetItemString (dict, "MAP_PRIVATE",
1112 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001113#endif
1114#ifdef MAP_DENYWRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001115 PyDict_SetItemString (dict, "MAP_DENYWRITE",
1116 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001117#endif
1118#ifdef MAP_EXECUTABLE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001119 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
1120 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001121#endif
1122#ifdef MAP_ANON
Guido van Rossum09fdf072000-03-31 01:17:07 +00001123 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
1124 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
1125 PyInt_FromLong(MAP_ANON) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001126#endif
1127
Guido van Rossum09fdf072000-03-31 01:17:07 +00001128 PyDict_SetItemString (dict, "PAGESIZE",
Fred Drake145f96e2000-10-01 17:50:46 +00001129 PyInt_FromLong( (long)my_getpagesize() ) );
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001130
Tim Peters5ebfd362001-11-13 23:11:19 +00001131 PyDict_SetItemString (dict, "ACCESS_READ",
1132 PyInt_FromLong(ACCESS_READ));
1133 PyDict_SetItemString (dict, "ACCESS_WRITE",
1134 PyInt_FromLong(ACCESS_WRITE));
1135 PyDict_SetItemString (dict, "ACCESS_COPY",
1136 PyInt_FromLong(ACCESS_COPY));
1137}