blob: 56033e8d4e88c222d6c0d9f0a67e78c9f0615891 [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
42#ifndef MS_SYNC
43/* This is missing e.g. on SunOS 4.1.4 */
44#define MS_SYNC 0
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000045#endif
46
Fred Drake145f96e2000-10-01 17:50:46 +000047#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
48static int
49my_getpagesize(void)
50{
Tim Peters5ebfd362001-11-13 23:11:19 +000051 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000052}
53#else
54#define my_getpagesize getpagesize
55#endif
56
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000057#endif /* UNIX */
58
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000059#include <string.h>
60#include <sys/types.h>
61
62static PyObject *mmap_module_error;
63
Tim Peters5ebfd362001-11-13 23:11:19 +000064typedef enum
65{
66 ACCESS_DEFAULT,
67 ACCESS_READ,
68 ACCESS_WRITE,
69 ACCESS_COPY
70} access_mode;
71
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000072typedef struct {
Guido van Rossum09fdf072000-03-31 01:17:07 +000073 PyObject_HEAD
74 char * data;
75 size_t size;
76 size_t pos;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000077
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000078#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +000079 HANDLE map_handle;
Mark Hammond071864a2000-07-30 02:46:26 +000080 HANDLE file_handle;
Guido van Rossum09fdf072000-03-31 01:17:07 +000081 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000082#endif
83
84#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000085 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000086#endif
Tim Peters5ebfd362001-11-13 23:11:19 +000087
88 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000089} mmap_object;
90
Tim Peters5ebfd362001-11-13 23:11:19 +000091
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000092static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +000093mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000094{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000095#ifdef MS_WINDOWS
Mark Hammond2cbed002000-07-30 02:22:43 +000096 if (m_obj->data != NULL)
97 UnmapViewOfFile (m_obj->data);
98 if (m_obj->map_handle != INVALID_HANDLE_VALUE)
99 CloseHandle (m_obj->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000100 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
101 CloseHandle (m_obj->file_handle);
Mark Hammond2cbed002000-07-30 02:22:43 +0000102 if (m_obj->tagname)
103 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000104#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000105
106#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000107 if (m_obj->data!=NULL) {
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000108 msync(m_obj->data, m_obj->size, MS_SYNC);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000109 munmap(m_obj->data, m_obj->size);
110 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000111#endif /* UNIX */
112
Guido van Rossumb18618d2000-05-03 23:44:39 +0000113 PyObject_Del(m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000114}
115
116static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000117mmap_close_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000118{
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000119 if (!PyArg_ParseTuple(args, ":close"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000120 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000121#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000122 /* For each resource we maintain, we need to check
123 the value is valid, and if so, free the resource
124 and set the member value to an invalid value so
125 the dealloc does not attempt to resource clearing
126 again.
127 TODO - should we check for errors in the close operations???
128 */
129 if (self->data != NULL) {
130 UnmapViewOfFile (self->data);
131 self->data = NULL;
132 }
133 if (self->map_handle != INVALID_HANDLE_VALUE) {
134 CloseHandle (self->map_handle);
135 self->map_handle = INVALID_HANDLE_VALUE;
136 }
137 if (self->file_handle != INVALID_HANDLE_VALUE) {
138 CloseHandle (self->file_handle);
139 self->file_handle = INVALID_HANDLE_VALUE;
140 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000141#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000142
143#ifdef UNIX
Neal Norwitze604c022003-01-10 20:52:16 +0000144 if (self->data != NULL) {
145 munmap(self->data, self->size);
146 self->data = NULL;
147 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000148#endif
149
Guido van Rossum09fdf072000-03-31 01:17:07 +0000150 Py_INCREF (Py_None);
151 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000152}
153
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000154#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +0000155#define CHECK_VALID(err) \
156do { \
Guido van Rossum69c2b882003-04-09 19:31:02 +0000157 if (self->map_handle == INVALID_HANDLE_VALUE) { \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000158 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
159 return err; \
160 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000161} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000162#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000163
164#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000165#define CHECK_VALID(err) \
166do { \
167 if (self->data == NULL) { \
168 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
169 return err; \
170 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000171} while (0)
172#endif /* UNIX */
173
174static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000175mmap_read_byte_method(mmap_object *self,
176 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000177{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000178 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000179 if (!PyArg_ParseTuple(args, ":read_byte"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000180 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000181 if (self->pos < self->size) {
Tim Petersd6283b82001-05-09 18:48:26 +0000182 char value = self->data[self->pos];
Guido van Rossum09fdf072000-03-31 01:17:07 +0000183 self->pos += 1;
Tim Petersd6283b82001-05-09 18:48:26 +0000184 return Py_BuildValue("c", value);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000185 } else {
186 PyErr_SetString (PyExc_ValueError, "read byte out of range");
187 return NULL;
188 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000189}
190
191static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000192mmap_read_line_method(mmap_object *self,
Tim Peters5ebfd362001-11-13 23:11:19 +0000193 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000194{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000195 char *start = self->data+self->pos;
196 char *eof = self->data+self->size;
197 char *eol;
198 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000199
Guido van Rossum09fdf072000-03-31 01:17:07 +0000200 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000201 if (!PyArg_ParseTuple(args, ":readline"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000202 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000203
Fred Drake56a87a02000-04-04 18:17:35 +0000204 eol = memchr(start, '\n', self->size - self->pos);
205 if (!eol)
206 eol = eof;
207 else
208 ++eol; /* we're interested in the position after the
209 newline. */
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000210 result = PyString_FromStringAndSize(start, (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000211 self->pos += (eol - start);
212 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000213}
214
215static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000216mmap_read_method(mmap_object *self,
217 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000218{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000219 long num_bytes;
220 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000221
Guido van Rossum09fdf072000-03-31 01:17:07 +0000222 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000223 if (!PyArg_ParseTuple(args, "l:read", &num_bytes))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000224 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000225
Guido van Rossum09fdf072000-03-31 01:17:07 +0000226 /* silently 'adjust' out-of-range requests */
227 if ((self->pos + num_bytes) > self->size) {
228 num_bytes -= (self->pos+num_bytes) - self->size;
229 }
230 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
231 self->pos += num_bytes;
232 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000233}
234
235static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000236mmap_find_method(mmap_object *self,
237 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000238{
Tim Petersd401edd2001-05-14 23:19:12 +0000239 long start = self->pos;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000240 char *needle;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000241 int len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000242
Guido van Rossum09fdf072000-03-31 01:17:07 +0000243 CHECK_VALID(NULL);
Tim Petersd401edd2001-05-14 23:19:12 +0000244 if (!PyArg_ParseTuple (args, "s#|l:find", &needle, &len, &start)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000245 return NULL;
246 } else {
Greg Stein834f4dd2001-05-14 09:32:26 +0000247 char *p;
248 char *e = self->data + self->size;
249
250 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000251 start += self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000252 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000253 start = 0;
Tim Petersd401edd2001-05-14 23:19:12 +0000254 else if ((size_t)start > self->size)
Tim Peters5ebfd362001-11-13 23:11:19 +0000255 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000256
Tim Petersc9ffa062002-03-08 05:43:32 +0000257 for (p = self->data + start; p + len <= e; ++p) {
258 int i;
259 for (i = 0; i < len && needle[i] == p[i]; ++i)
260 /* nothing */;
261 if (i == len) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000262 return Py_BuildValue (
Tim Petersd401edd2001-05-14 23:19:12 +0000263 "l",
264 (long) (p - self->data));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000265 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000266 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000267 return Py_BuildValue ("l", (long) -1);
268 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000269}
270
Tim Peters5ebfd362001-11-13 23:11:19 +0000271static int
272is_writeable(mmap_object *self)
273{
274 if (self->access != ACCESS_READ)
275 return 1;
276 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
277 return 0;
278}
279
280static int
281is_resizeable(mmap_object *self)
282{
283 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
284 return 1;
285 PyErr_Format(PyExc_TypeError,
286 "mmap can't resize a readonly or copy-on-write memory map.");
287 return 0;
288}
289
290
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000291static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000292mmap_write_method(mmap_object *self,
293 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000294{
Neal Norwitz4d933fe2003-02-07 19:44:56 +0000295 int length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000296 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000297
Guido van Rossum09fdf072000-03-31 01:17:07 +0000298 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000299 if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000300 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000301
Tim Peters5ebfd362001-11-13 23:11:19 +0000302 if (!is_writeable(self))
303 return NULL;
304
Guido van Rossum09fdf072000-03-31 01:17:07 +0000305 if ((self->pos + length) > self->size) {
306 PyErr_SetString (PyExc_ValueError, "data out of range");
307 return NULL;
308 }
309 memcpy (self->data+self->pos, data, length);
310 self->pos = self->pos+length;
311 Py_INCREF (Py_None);
312 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000313}
314
315static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000316mmap_write_byte_method(mmap_object *self,
317 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000318{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000319 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000320
Guido van Rossum09fdf072000-03-31 01:17:07 +0000321 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000322 if (!PyArg_ParseTuple (args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000323 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000324
Tim Peters5ebfd362001-11-13 23:11:19 +0000325 if (!is_writeable(self))
326 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000327 *(self->data+self->pos) = value;
328 self->pos += 1;
329 Py_INCREF (Py_None);
330 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000331}
Tim Peters5ebfd362001-11-13 23:11:19 +0000332
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000333static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000334mmap_size_method(mmap_object *self,
335 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000336{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000337 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000338 if (!PyArg_ParseTuple(args, ":size"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000339 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000340
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000341#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000342 if (self->file_handle != INVALID_HANDLE_VALUE) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000343 return (Py_BuildValue (
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000344 "l", (long)
Mark Hammond071864a2000-07-30 02:46:26 +0000345 GetFileSize (self->file_handle, NULL)));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000346 } else {
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000347 return (Py_BuildValue ("l", (long) self->size) );
Guido van Rossum09fdf072000-03-31 01:17:07 +0000348 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000349#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000350
351#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000352 {
353 struct stat buf;
354 if (-1 == fstat(self->fd, &buf)) {
355 PyErr_SetFromErrno(mmap_module_error);
356 return NULL;
357 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000358 return (Py_BuildValue ("l", (long) buf.st_size) );
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000359 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000360#endif /* UNIX */
361}
362
363/* This assumes that you want the entire file mapped,
364 / and when recreating the map will make the new file
365 / have the new size
366 /
367 / Is this really necessary? This could easily be done
368 / from python by just closing and re-opening with the
369 / new size?
370 */
371
372static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000373mmap_resize_method(mmap_object *self,
374 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000375{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000376 unsigned long new_size;
377 CHECK_VALID(NULL);
Tim Peters5ebfd362001-11-13 23:11:19 +0000378 if (!PyArg_ParseTuple (args, "l:resize", &new_size) ||
379 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000380 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000381#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +0000382 } else {
383 DWORD dwErrCode = 0;
384 /* First, unmap the file view */
385 UnmapViewOfFile (self->data);
386 /* Close the mapping object */
Mark Hammond071864a2000-07-30 02:46:26 +0000387 CloseHandle (self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000388 /* Move to the desired EOF position */
Mark Hammond071864a2000-07-30 02:46:26 +0000389 SetFilePointer (self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000390 new_size, NULL, FILE_BEGIN);
391 /* Change the size of the file */
Mark Hammond071864a2000-07-30 02:46:26 +0000392 SetEndOfFile (self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000393 /* Create another mapping object and remap the file view */
394 self->map_handle = CreateFileMapping (
Mark Hammond071864a2000-07-30 02:46:26 +0000395 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000396 NULL,
397 PAGE_READWRITE,
398 0,
399 new_size,
400 self->tagname);
401 if (self->map_handle != NULL) {
402 self->data = (char *) MapViewOfFile (self->map_handle,
403 FILE_MAP_WRITE,
404 0,
405 0,
406 0);
407 if (self->data != NULL) {
408 self->size = new_size;
409 Py_INCREF (Py_None);
410 return Py_None;
411 } else {
412 dwErrCode = GetLastError();
413 }
414 } else {
415 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000416 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000417 PyErr_SetFromWindowsErr(dwErrCode);
418 return (NULL);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000419#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000420
421#ifdef UNIX
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000422#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000423 } else {
424 PyErr_SetString(PyExc_SystemError,
425 "mmap: resizing not available--no mremap()");
426 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000427#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000428 } else {
429 void *newmap;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000430
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000431#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000432 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000433#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000434 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000435#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000436 if (newmap == (void *)-1)
437 {
438 PyErr_SetFromErrno(mmap_module_error);
439 return NULL;
440 }
441 self->data = newmap;
442 self->size = new_size;
443 Py_INCREF(Py_None);
444 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000445#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000446#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000447 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000448}
449
450static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000451mmap_tell_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000452{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000453 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000454 if (!PyArg_ParseTuple(args, ":tell"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000455 return NULL;
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000456 return (Py_BuildValue ("l", (long) self->pos) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000457}
458
459static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000460mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000461{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000462 size_t offset = 0;
463 size_t size = self->size;
464 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000465 if (!PyArg_ParseTuple (args, "|ll:flush", &offset, &size)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000466 return NULL;
467 } else if ((offset + size) > self->size) {
468 PyErr_SetString (PyExc_ValueError,
469 "flush values out of range");
470 return NULL;
471 } else {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000472#ifdef MS_WINDOWS
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000473 return (Py_BuildValue("l", (long)
474 FlushViewOfFile(self->data+offset, size)));
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000475#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000476#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000477 /* XXX semantics of return value? */
478 /* XXX flags for msync? */
479 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000480 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000481 {
482 PyErr_SetFromErrno(mmap_module_error);
483 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000484 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000485 return Py_BuildValue ("l", (long) 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000486#endif /* UNIX */
487 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000488}
489
490static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000491mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000492{
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000493 int dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000494 int how=0;
495 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000496 if (!PyArg_ParseTuple (args, "i|i:seek", &dist, &how)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000497 return(NULL);
498 } else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000499 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000500 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000501 case 0: /* relative to start */
502 if (dist < 0)
503 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000504 where = dist;
505 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000506 case 1: /* relative to current position */
507 if ((int)self->pos + dist < 0)
508 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000509 where = self->pos + dist;
510 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000511 case 2: /* relative to end */
512 if ((int)self->size + dist < 0)
513 goto onoutofrange;
514 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000515 break;
516 default:
517 PyErr_SetString (PyExc_ValueError,
518 "unknown seek type");
519 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000520 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000521 if (where > self->size)
522 goto onoutofrange;
523 self->pos = where;
524 Py_INCREF (Py_None);
525 return (Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000526 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000527
Tim Peters5ebfd362001-11-13 23:11:19 +0000528 onoutofrange:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000529 PyErr_SetString (PyExc_ValueError, "seek out of range");
530 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000531}
532
533static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000534mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000535{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000536 unsigned long dest, src, count;
537 CHECK_VALID(NULL);
Tim Peters5ebfd362001-11-13 23:11:19 +0000538 if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count) ||
539 !is_writeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000540 return NULL;
541 } else {
542 /* bounds check the values */
543 if (/* end of source after end of data?? */
544 ((src+count) > self->size)
545 /* dest will fit? */
546 || (dest+count > self->size)) {
547 PyErr_SetString (PyExc_ValueError,
548 "source or destination out of range");
549 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000550 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000551 memmove (self->data+dest, self->data+src, count);
552 Py_INCREF (Py_None);
553 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000554 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000555 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000556}
557
558static struct PyMethodDef mmap_object_methods[] = {
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000559 {"close", (PyCFunction) mmap_close_method, METH_VARARGS},
560 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
561 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
562 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
563 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
564 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_VARARGS},
565 {"readline", (PyCFunction) mmap_read_line_method, METH_VARARGS},
566 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
567 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
568 {"size", (PyCFunction) mmap_size_method, METH_VARARGS},
569 {"tell", (PyCFunction) mmap_tell_method, METH_VARARGS},
570 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
571 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000572 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000573};
574
575/* Functions for treating an mmap'ed file as a buffer */
576
577static int
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000578mmap_buffer_getreadbuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000579{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000580 CHECK_VALID(-1);
581 if ( index != 0 ) {
582 PyErr_SetString(PyExc_SystemError,
583 "Accessing non-existent mmap segment");
584 return -1;
585 }
586 *ptr = self->data;
587 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000588}
589
590static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000591mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000592{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000593 CHECK_VALID(-1);
594 if ( index != 0 ) {
595 PyErr_SetString(PyExc_SystemError,
596 "Accessing non-existent mmap segment");
597 return -1;
598 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000599 if (!is_writeable(self))
600 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000601 *ptr = self->data;
602 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000603}
604
605static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000606mmap_buffer_getsegcount(mmap_object *self, int *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000607{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000608 CHECK_VALID(-1);
609 if (lenp)
610 *lenp = self->size;
611 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000612}
613
614static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000615mmap_buffer_getcharbuffer(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000616{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000617 if ( index != 0 ) {
618 PyErr_SetString(PyExc_SystemError,
619 "accessing non-existent buffer segment");
620 return -1;
621 }
622 *ptr = (const char *)self->data;
623 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000624}
625
626static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000627mmap_object_getattr(mmap_object *self, char *name)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000628{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000629 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000630}
631
632static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000633mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000634{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000635 CHECK_VALID(-1);
636 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000637}
638
639static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000640mmap_item(mmap_object *self, int i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000641{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000642 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000643 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000644 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
645 return NULL;
646 }
647 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000648}
649
650static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000651mmap_slice(mmap_object *self, int ilow, int ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000652{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000653 CHECK_VALID(NULL);
654 if (ilow < 0)
655 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000656 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000657 ilow = self->size;
658 if (ihigh < 0)
659 ihigh = 0;
660 if (ihigh < ilow)
661 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000662 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000663 ihigh = self->size;
664
665 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000666}
667
668static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000669mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000670{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000671 CHECK_VALID(NULL);
672 PyErr_SetString(PyExc_SystemError,
673 "mmaps don't support concatenation");
674 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000675}
676
677static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000678mmap_repeat(mmap_object *self, int n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000679{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000680 CHECK_VALID(NULL);
681 PyErr_SetString(PyExc_SystemError,
682 "mmaps don't support repeat operation");
683 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000684}
685
686static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000687mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000688{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000689 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000690
Guido van Rossum09fdf072000-03-31 01:17:07 +0000691 CHECK_VALID(-1);
692 if (ilow < 0)
693 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000694 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000695 ilow = self->size;
696 if (ihigh < 0)
697 ihigh = 0;
698 if (ihigh < ilow)
699 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000700 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000701 ihigh = self->size;
702
Thomas Wouters1baac722001-07-16 15:47:36 +0000703 if (v == NULL) {
704 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000705 "mmap object doesn't support slice deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000706 return -1;
707 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000708 if (! (PyString_Check(v)) ) {
709 PyErr_SetString(PyExc_IndexError,
710 "mmap slice assignment must be a string");
711 return -1;
712 }
713 if ( PyString_Size(v) != (ihigh - ilow) ) {
714 PyErr_SetString(PyExc_IndexError,
715 "mmap slice assignment is wrong size");
716 return -1;
717 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000718 if (!is_writeable(self))
719 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000720 buf = PyString_AsString(v);
721 memcpy(self->data + ilow, buf, ihigh-ilow);
722 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000723}
724
725static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000726mmap_ass_item(mmap_object *self, int i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000727{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000728 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000729
Guido van Rossum09fdf072000-03-31 01:17:07 +0000730 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000731 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000732 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
733 return -1;
734 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000735 if (v == NULL) {
736 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000737 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000738 return -1;
739 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000740 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
741 PyErr_SetString(PyExc_IndexError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000742 "mmap assignment must be single-character string");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000743 return -1;
744 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000745 if (!is_writeable(self))
746 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000747 buf = PyString_AsString(v);
748 self->data[i] = buf[0];
749 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000750}
751
752static PySequenceMethods mmap_as_sequence = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000753 (inquiry)mmap_length, /*sq_length*/
754 (binaryfunc)mmap_concat, /*sq_concat*/
755 (intargfunc)mmap_repeat, /*sq_repeat*/
756 (intargfunc)mmap_item, /*sq_item*/
757 (intintargfunc)mmap_slice, /*sq_slice*/
758 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
759 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000760};
761
762static PyBufferProcs mmap_as_buffer = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000763 (getreadbufferproc)mmap_buffer_getreadbuf,
764 (getwritebufferproc)mmap_buffer_getwritebuf,
765 (getsegcountproc)mmap_buffer_getsegcount,
766 (getcharbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000767};
768
769static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000770 PyObject_HEAD_INIT(0) /* patched in module init */
771 0, /* ob_size */
Guido van Rossum14648392001-12-08 18:02:58 +0000772 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000773 sizeof(mmap_object), /* tp_size */
774 0, /* tp_itemsize */
775 /* methods */
776 (destructor) mmap_object_dealloc, /* tp_dealloc */
777 0, /* tp_print */
778 (getattrfunc) mmap_object_getattr, /* tp_getattr */
779 0, /* tp_setattr */
780 0, /* tp_compare */
781 0, /* tp_repr */
782 0, /* tp_as_number */
783 &mmap_as_sequence, /*tp_as_sequence*/
784 0, /*tp_as_mapping*/
785 0, /*tp_hash*/
786 0, /*tp_call*/
787 0, /*tp_str*/
788 0, /*tp_getattro*/
789 0, /*tp_setattro*/
790 &mmap_as_buffer, /*tp_as_buffer*/
791 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
792 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000793};
794
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000795
796/* extract the map size from the given PyObject
797
798 The map size is restricted to [0, INT_MAX] because this is the current
799 Python limitation on object sizes. Although the mmap object *could* handle
800 a larger map size, there is no point because all the useful operations
801 (len(), slicing(), sequence indexing) are limited by a C int.
802
Thomas Wouters7e474022000-07-16 12:04:32 +0000803 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000804 success, the map size is returned. */
805static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000806_GetMapSize(PyObject *o)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000807{
808 if (PyInt_Check(o)) {
809 long i = PyInt_AsLong(o);
810 if (PyErr_Occurred())
811 return -1;
812 if (i < 0)
813 goto onnegoverflow;
814 if (i > INT_MAX)
815 goto onposoverflow;
816 return (int)i;
817 }
818 else if (PyLong_Check(o)) {
819 long i = PyLong_AsLong(o);
820 if (PyErr_Occurred()) {
821 /* yes negative overflow is mistaken for positive overflow
822 but not worth the trouble to check sign of 'i' */
823 if (PyErr_ExceptionMatches(PyExc_OverflowError))
824 goto onposoverflow;
825 else
826 return -1;
827 }
828 if (i < 0)
829 goto onnegoverflow;
830 if (i > INT_MAX)
831 goto onposoverflow;
832 return (int)i;
833 }
834 else {
835 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000836 "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000837 return -1;
838 }
839
Tim Peters5ebfd362001-11-13 23:11:19 +0000840 onnegoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000841 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000842 "memory mapped size must be positive");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000843 return -1;
844
Tim Peters5ebfd362001-11-13 23:11:19 +0000845 onposoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000846 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000847 "memory mapped size is too large (limited by C int)");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000848 return -1;
849}
850
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000851#ifdef UNIX
852static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000853new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000854{
Neal Norwitzb5673922002-09-05 21:48:07 +0000855#ifdef HAVE_FSTAT
856 struct stat st;
857#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000858 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000859 PyObject *map_size_obj = NULL;
860 int map_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000861 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Tim Peters5ebfd362001-11-13 23:11:19 +0000862 access_mode access = ACCESS_DEFAULT;
863 char *keywords[] = {"fileno", "length",
864 "flags", "prot",
865 "access", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000866
Tim Peters5ebfd362001-11-13 23:11:19 +0000867 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii", keywords,
868 &fd, &map_size_obj, &flags, &prot, &access))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000869 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000870 map_size = _GetMapSize(map_size_obj);
871 if (map_size < 0)
872 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000873
874 if ((access != ACCESS_DEFAULT) &&
875 ((flags != MAP_SHARED) || ( prot != (PROT_WRITE | PROT_READ))))
876 return PyErr_Format(PyExc_ValueError,
877 "mmap can't specify both access and flags, prot.");
878 switch(access) {
879 case ACCESS_READ:
880 flags = MAP_SHARED;
881 prot = PROT_READ;
882 break;
883 case ACCESS_WRITE:
884 flags = MAP_SHARED;
885 prot = PROT_READ | PROT_WRITE;
886 break;
887 case ACCESS_COPY:
888 flags = MAP_PRIVATE;
889 prot = PROT_READ | PROT_WRITE;
890 break;
891 case ACCESS_DEFAULT:
892 /* use the specified or default values of flags and prot */
893 break;
894 default:
895 return PyErr_Format(PyExc_ValueError,
896 "mmap invalid access parameter.");
897 }
Neal Norwitzb5673922002-09-05 21:48:07 +0000898
899#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +0000900# ifdef __VMS
901 /* on OpenVMS we must ensure that all bytes are written to the file */
902 fsync(fd);
903# endif
Neal Norwitzb5673922002-09-05 21:48:07 +0000904 if (fstat(fd, &st) == 0 && (size_t)map_size > st.st_size) {
905 PyErr_SetString(PyExc_ValueError,
906 "mmap length is greater than file size");
907 return NULL;
908 }
909#endif
Guido van Rossumb18618d2000-05-03 23:44:39 +0000910 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000911 if (m_obj == NULL) {return NULL;}
912 m_obj->size = (size_t) map_size;
913 m_obj->pos = (size_t) 0;
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000914 m_obj->fd = fd;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000915 m_obj->data = mmap(NULL, map_size,
916 prot, flags,
917 fd, 0);
Tim Peters5ebfd362001-11-13 23:11:19 +0000918 if (m_obj->data == (char *)-1) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000919 Py_DECREF(m_obj);
920 PyErr_SetFromErrno(mmap_module_error);
921 return NULL;
922 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000923 m_obj->access = access;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000924 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000925}
926#endif /* UNIX */
927
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000928#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000929static PyObject *
Tim Peters5ebfd362001-11-13 23:11:19 +0000930new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000931{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000932 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000933 PyObject *map_size_obj = NULL;
934 int map_size;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000935 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +0000936 DWORD dwErr = 0;
937 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +0000938 HANDLE fh = 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000939 access_mode access = ACCESS_DEFAULT;
940 DWORD flProtect, dwDesiredAccess;
941 char *keywords[] = { "fileno", "length",
942 "tagname",
943 "access", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000944
Tim Peters5ebfd362001-11-13 23:11:19 +0000945 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|zi", keywords,
946 &fileno, &map_size_obj,
947 &tagname, &access)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000948 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000949 }
950
951 switch(access) {
952 case ACCESS_READ:
953 flProtect = PAGE_READONLY;
954 dwDesiredAccess = FILE_MAP_READ;
955 break;
956 case ACCESS_DEFAULT: case ACCESS_WRITE:
957 flProtect = PAGE_READWRITE;
958 dwDesiredAccess = FILE_MAP_WRITE;
959 break;
960 case ACCESS_COPY:
961 flProtect = PAGE_WRITECOPY;
962 dwDesiredAccess = FILE_MAP_COPY;
963 break;
964 default:
965 return PyErr_Format(PyExc_ValueError,
966 "mmap invalid access parameter.");
967 }
968
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000969 map_size = _GetMapSize(map_size_obj);
970 if (map_size < 0)
971 return NULL;
972
Guido van Rossum09fdf072000-03-31 01:17:07 +0000973 /* if an actual filename has been specified */
974 if (fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +0000975 fh = (HANDLE)_get_osfhandle(fileno);
976 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +0000977 PyErr_SetFromErrno(mmap_module_error);
978 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000979 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +0000980 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +0000981 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000982 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000983
Guido van Rossumb18618d2000-05-03 23:44:39 +0000984 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Mark Hammond2cbed002000-07-30 02:22:43 +0000985 if (m_obj==NULL)
986 return NULL;
987 /* Set every field to an invalid marker, so we can safely
988 destruct the object in the face of failure */
989 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +0000990 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +0000991 m_obj->map_handle = INVALID_HANDLE_VALUE;
992 m_obj->tagname = NULL;
993
Guido van Rossum09fdf072000-03-31 01:17:07 +0000994 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +0000995 /* It is necessary to duplicate the handle, so the
996 Python code can close it on us */
997 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +0000998 GetCurrentProcess(), /* source process handle */
999 fh, /* handle to be duplicated */
1000 GetCurrentProcess(), /* target proc handle */
1001 (LPHANDLE)&m_obj->file_handle, /* result */
1002 0, /* access - ignored due to options value */
1003 FALSE, /* inherited by child processes? */
1004 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001005 dwErr = GetLastError();
1006 Py_DECREF(m_obj);
1007 PyErr_SetFromWindowsErr(dwErr);
1008 return NULL;
1009 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001010 if (!map_size) {
Mark Hammond071864a2000-07-30 02:46:26 +00001011 m_obj->size = GetFileSize (fh, NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001012 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001013 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001014 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001015 }
1016 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001017 m_obj->size = map_size;
1018 }
1019
1020 /* set the initial position */
1021 m_obj->pos = (size_t) 0;
1022
Mark Hammond2cbed002000-07-30 02:22:43 +00001023 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001024 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001025 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1026 if (m_obj->tagname == NULL) {
1027 PyErr_NoMemory();
1028 Py_DECREF(m_obj);
1029 return NULL;
1030 }
1031 strcpy(m_obj->tagname, tagname);
1032 }
1033 else
1034 m_obj->tagname = NULL;
1035
Tim Peters5ebfd362001-11-13 23:11:19 +00001036 m_obj->access = access;
Mark Hammond071864a2000-07-30 02:46:26 +00001037 m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001038 NULL,
Tim Peters5ebfd362001-11-13 23:11:19 +00001039 flProtect,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001040 0,
1041 m_obj->size,
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001042 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001043 if (m_obj->map_handle != NULL) {
1044 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
Tim Peters5ebfd362001-11-13 23:11:19 +00001045 dwDesiredAccess,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001046 0,
1047 0,
1048 0);
1049 if (m_obj->data != NULL) {
1050 return ((PyObject *) m_obj);
1051 } else {
Tim Peters5ebfd362001-11-13 23:11:19 +00001052 dwErr = GetLastError();
Guido van Rossum09fdf072000-03-31 01:17:07 +00001053 }
1054 } else {
1055 dwErr = GetLastError();
1056 }
Mark Hammond2cbed002000-07-30 02:22:43 +00001057 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001058 PyErr_SetFromWindowsErr(dwErr);
1059 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001060}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001061#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001062
1063/* List of functions exported by this module */
1064static struct PyMethodDef mmap_functions[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001065 {"mmap", (PyCFunction) new_mmap_object,
1066 METH_VARARGS|METH_KEYWORDS},
1067 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001068};
1069
Mark Hammond62b1ab12002-07-23 06:31:15 +00001070PyMODINIT_FUNC
Tim Peters5ebfd362001-11-13 23:11:19 +00001071 initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001072{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001073 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001074
1075 /* Patch the object type */
1076 mmap_object_type.ob_type = &PyType_Type;
1077
Guido van Rossum09fdf072000-03-31 01:17:07 +00001078 module = Py_InitModule ("mmap", mmap_functions);
1079 dict = PyModule_GetDict (module);
1080 mmap_module_error = PyExc_EnvironmentError;
1081 Py_INCREF(mmap_module_error);
1082 PyDict_SetItemString (dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001083#ifdef PROT_EXEC
Guido van Rossum09fdf072000-03-31 01:17:07 +00001084 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001085#endif
1086#ifdef PROT_READ
Guido van Rossum09fdf072000-03-31 01:17:07 +00001087 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001088#endif
1089#ifdef PROT_WRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001090 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001091#endif
1092
1093#ifdef MAP_SHARED
Guido van Rossum09fdf072000-03-31 01:17:07 +00001094 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001095#endif
1096#ifdef MAP_PRIVATE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001097 PyDict_SetItemString (dict, "MAP_PRIVATE",
1098 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001099#endif
1100#ifdef MAP_DENYWRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001101 PyDict_SetItemString (dict, "MAP_DENYWRITE",
1102 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001103#endif
1104#ifdef MAP_EXECUTABLE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001105 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
1106 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001107#endif
1108#ifdef MAP_ANON
Guido van Rossum09fdf072000-03-31 01:17:07 +00001109 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
1110 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
1111 PyInt_FromLong(MAP_ANON) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001112#endif
1113
Guido van Rossum09fdf072000-03-31 01:17:07 +00001114 PyDict_SetItemString (dict, "PAGESIZE",
Fred Drake145f96e2000-10-01 17:50:46 +00001115 PyInt_FromLong( (long)my_getpagesize() ) );
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001116
Tim Peters5ebfd362001-11-13 23:11:19 +00001117 PyDict_SetItemString (dict, "ACCESS_READ",
1118 PyInt_FromLong(ACCESS_READ));
1119 PyDict_SetItemString (dict, "ACCESS_WRITE",
1120 PyInt_FromLong(ACCESS_WRITE));
1121 PyDict_SetItemString (dict, "ACCESS_COPY",
1122 PyInt_FromLong(ACCESS_COPY));
1123}