blob: dbb3fcdde903afc7584cf167d183f37abe474c3d [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);
Neal Norwitz8856fb72005-12-18 03:34:22 +0000377 if (!PyArg_ParseTuple (args, "k:resize", &new_size) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000378 !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{
Neal Norwitz8856fb72005-12-18 03:34:22 +0000466 unsigned long offset = 0;
467 unsigned long size = self->size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000468 CHECK_VALID(NULL);
Neal Norwitz8856fb72005-12-18 03:34:22 +0000469 if (!PyArg_ParseTuple (args, "|kk: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);
Neal Norwitz8856fb72005-12-18 03:34:22 +0000542 if (!PyArg_ParseTuple (args, "kkk:move", &dest, &src, &count) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000543 !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;
Neal Norwitz8856fb72005-12-18 03:34:22 +0000866 int access = (int)ACCESS_DEFAULT;
Jeremy Hyltonaf68c872005-12-10 18:50:16 +0000867 static const 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,
Jeremy Hyltonaf68c872005-12-10 18:50:16 +0000872 &fd, &map_size_obj, &flags, &prot,
873 &access))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000874 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000875 map_size = _GetMapSize(map_size_obj);
876 if (map_size < 0)
877 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000878
Neal Norwitz8856fb72005-12-18 03:34:22 +0000879 if ((access != (int)ACCESS_DEFAULT) &&
Tim Peters5ebfd362001-11-13 23:11:19 +0000880 ((flags != MAP_SHARED) || ( prot != (PROT_WRITE | PROT_READ))))
881 return PyErr_Format(PyExc_ValueError,
882 "mmap can't specify both access and flags, prot.");
Neal Norwitz8856fb72005-12-18 03:34:22 +0000883 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +0000884 case ACCESS_READ:
885 flags = MAP_SHARED;
886 prot = PROT_READ;
887 break;
888 case ACCESS_WRITE:
889 flags = MAP_SHARED;
890 prot = PROT_READ | PROT_WRITE;
891 break;
892 case ACCESS_COPY:
893 flags = MAP_PRIVATE;
894 prot = PROT_READ | PROT_WRITE;
895 break;
896 case ACCESS_DEFAULT:
897 /* use the specified or default values of flags and prot */
898 break;
899 default:
900 return PyErr_Format(PyExc_ValueError,
901 "mmap invalid access parameter.");
902 }
Neal Norwitzb5673922002-09-05 21:48:07 +0000903
904#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +0000905# ifdef __VMS
906 /* on OpenVMS we must ensure that all bytes are written to the file */
907 fsync(fd);
908# endif
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000909 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
910 if (map_size == 0) {
911 map_size = (int)st.st_size;
912 } else if ((size_t)map_size > st.st_size) {
913 PyErr_SetString(PyExc_ValueError,
914 "mmap length is greater than file size");
915 return NULL;
916 }
Neal Norwitzb5673922002-09-05 21:48:07 +0000917 }
918#endif
Guido van Rossumb18618d2000-05-03 23:44:39 +0000919 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000920 if (m_obj == NULL) {return NULL;}
921 m_obj->size = (size_t) map_size;
922 m_obj->pos = (size_t) 0;
Georg Brandl38387b82005-08-24 07:17:40 +0000923 m_obj->fd = dup(fd);
924 if (m_obj->fd == -1) {
925 Py_DECREF(m_obj);
926 PyErr_SetFromErrno(mmap_module_error);
927 return NULL;
928 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000929 m_obj->data = mmap(NULL, map_size,
930 prot, flags,
931 fd, 0);
Tim Peters5ebfd362001-11-13 23:11:19 +0000932 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +0000933 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000934 Py_DECREF(m_obj);
935 PyErr_SetFromErrno(mmap_module_error);
936 return NULL;
937 }
Neal Norwitz8856fb72005-12-18 03:34:22 +0000938 m_obj->access = (access_mode)access;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000939 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000940}
941#endif /* UNIX */
942
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000943#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000944static PyObject *
Tim Peters5ebfd362001-11-13 23:11:19 +0000945new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000946{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000947 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000948 PyObject *map_size_obj = NULL;
949 int map_size;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000950 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +0000951 DWORD dwErr = 0;
952 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +0000953 HANDLE fh = 0;
Neal Norwitz8856fb72005-12-18 03:34:22 +0000954 int access = (access_mode)ACCESS_DEFAULT;
Tim Peters5ebfd362001-11-13 23:11:19 +0000955 DWORD flProtect, dwDesiredAccess;
Jeremy Hyltonaf68c872005-12-10 18:50:16 +0000956 static const char *keywords[] = { "fileno", "length",
957 "tagname",
958 "access", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000959
Tim Peters5ebfd362001-11-13 23:11:19 +0000960 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|zi", keywords,
961 &fileno, &map_size_obj,
962 &tagname, &access)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000963 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000964 }
965
Neal Norwitz8856fb72005-12-18 03:34:22 +0000966 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +0000967 case ACCESS_READ:
968 flProtect = PAGE_READONLY;
969 dwDesiredAccess = FILE_MAP_READ;
970 break;
971 case ACCESS_DEFAULT: case ACCESS_WRITE:
972 flProtect = PAGE_READWRITE;
973 dwDesiredAccess = FILE_MAP_WRITE;
974 break;
975 case ACCESS_COPY:
976 flProtect = PAGE_WRITECOPY;
977 dwDesiredAccess = FILE_MAP_COPY;
978 break;
979 default:
980 return PyErr_Format(PyExc_ValueError,
981 "mmap invalid access parameter.");
982 }
983
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000984 map_size = _GetMapSize(map_size_obj);
985 if (map_size < 0)
986 return NULL;
987
Guido van Rossum09fdf072000-03-31 01:17:07 +0000988 /* if an actual filename has been specified */
989 if (fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +0000990 fh = (HANDLE)_get_osfhandle(fileno);
991 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +0000992 PyErr_SetFromErrno(mmap_module_error);
993 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000994 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +0000995 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +0000996 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000997 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000998
Guido van Rossumb18618d2000-05-03 23:44:39 +0000999 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Mark Hammond2cbed002000-07-30 02:22:43 +00001000 if (m_obj==NULL)
1001 return NULL;
1002 /* Set every field to an invalid marker, so we can safely
1003 destruct the object in the face of failure */
1004 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001005 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +00001006 m_obj->map_handle = INVALID_HANDLE_VALUE;
1007 m_obj->tagname = NULL;
1008
Guido van Rossum09fdf072000-03-31 01:17:07 +00001009 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001010 /* It is necessary to duplicate the handle, so the
1011 Python code can close it on us */
1012 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001013 GetCurrentProcess(), /* source process handle */
1014 fh, /* handle to be duplicated */
1015 GetCurrentProcess(), /* target proc handle */
1016 (LPHANDLE)&m_obj->file_handle, /* result */
1017 0, /* access - ignored due to options value */
1018 FALSE, /* inherited by child processes? */
1019 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001020 dwErr = GetLastError();
1021 Py_DECREF(m_obj);
1022 PyErr_SetFromWindowsErr(dwErr);
1023 return NULL;
1024 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001025 if (!map_size) {
Mark Hammond071864a2000-07-30 02:46:26 +00001026 m_obj->size = GetFileSize (fh, NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001027 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001028 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001029 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001030 }
1031 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001032 m_obj->size = map_size;
1033 }
1034
1035 /* set the initial position */
1036 m_obj->pos = (size_t) 0;
1037
Mark Hammond2cbed002000-07-30 02:22:43 +00001038 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001039 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001040 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1041 if (m_obj->tagname == NULL) {
1042 PyErr_NoMemory();
1043 Py_DECREF(m_obj);
1044 return NULL;
1045 }
1046 strcpy(m_obj->tagname, tagname);
1047 }
1048 else
1049 m_obj->tagname = NULL;
1050
Neal Norwitz8856fb72005-12-18 03:34:22 +00001051 m_obj->access = (access_mode)access;
Mark Hammond071864a2000-07-30 02:46:26 +00001052 m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001053 NULL,
Tim Peters5ebfd362001-11-13 23:11:19 +00001054 flProtect,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001055 0,
1056 m_obj->size,
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001057 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001058 if (m_obj->map_handle != NULL) {
1059 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
Tim Peters5ebfd362001-11-13 23:11:19 +00001060 dwDesiredAccess,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001061 0,
1062 0,
1063 0);
1064 if (m_obj->data != NULL) {
1065 return ((PyObject *) m_obj);
1066 } else {
Tim Peters5ebfd362001-11-13 23:11:19 +00001067 dwErr = GetLastError();
Guido van Rossum09fdf072000-03-31 01:17:07 +00001068 }
1069 } else {
1070 dwErr = GetLastError();
1071 }
Mark Hammond2cbed002000-07-30 02:22:43 +00001072 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001073 PyErr_SetFromWindowsErr(dwErr);
1074 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001075}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001076#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001077
1078/* List of functions exported by this module */
1079static struct PyMethodDef mmap_functions[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001080 {"mmap", (PyCFunction) new_mmap_object,
1081 METH_VARARGS|METH_KEYWORDS},
1082 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001083};
1084
Mark Hammond62b1ab12002-07-23 06:31:15 +00001085PyMODINIT_FUNC
Tim Peters5ebfd362001-11-13 23:11:19 +00001086 initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001087{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001088 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001089
1090 /* Patch the object type */
1091 mmap_object_type.ob_type = &PyType_Type;
1092
Guido van Rossum09fdf072000-03-31 01:17:07 +00001093 module = Py_InitModule ("mmap", mmap_functions);
1094 dict = PyModule_GetDict (module);
1095 mmap_module_error = PyExc_EnvironmentError;
1096 Py_INCREF(mmap_module_error);
1097 PyDict_SetItemString (dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001098#ifdef PROT_EXEC
Guido van Rossum09fdf072000-03-31 01:17:07 +00001099 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001100#endif
1101#ifdef PROT_READ
Guido van Rossum09fdf072000-03-31 01:17:07 +00001102 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001103#endif
1104#ifdef PROT_WRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001105 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001106#endif
1107
1108#ifdef MAP_SHARED
Guido van Rossum09fdf072000-03-31 01:17:07 +00001109 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001110#endif
1111#ifdef MAP_PRIVATE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001112 PyDict_SetItemString (dict, "MAP_PRIVATE",
1113 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001114#endif
1115#ifdef MAP_DENYWRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001116 PyDict_SetItemString (dict, "MAP_DENYWRITE",
1117 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001118#endif
1119#ifdef MAP_EXECUTABLE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001120 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
1121 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001122#endif
1123#ifdef MAP_ANON
Guido van Rossum09fdf072000-03-31 01:17:07 +00001124 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
1125 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
1126 PyInt_FromLong(MAP_ANON) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001127#endif
1128
Guido van Rossum09fdf072000-03-31 01:17:07 +00001129 PyDict_SetItemString (dict, "PAGESIZE",
Fred Drake145f96e2000-10-01 17:50:46 +00001130 PyInt_FromLong( (long)my_getpagesize() ) );
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001131
Tim Peters5ebfd362001-11-13 23:11:19 +00001132 PyDict_SetItemString (dict, "ACCESS_READ",
1133 PyInt_FromLong(ACCESS_READ));
1134 PyDict_SetItemString (dict, "ACCESS_WRITE",
1135 PyInt_FromLong(ACCESS_WRITE));
1136 PyDict_SetItemString (dict, "ACCESS_COPY",
1137 PyInt_FromLong(ACCESS_COPY));
1138}