blob: a4ec2d0fe553a4cfbf20af60ccbc715db58c691c [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
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000023#ifndef MS_WIN32
24#define UNIX
25#endif
26
27#ifdef MS_WIN32
28#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
39#include <unistd.h>
40#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000041#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000042
43#ifndef MS_SYNC
44/* This is missing e.g. on SunOS 4.1.4 */
45#define MS_SYNC 0
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000046#endif
47
Fred Drake145f96e2000-10-01 17:50:46 +000048#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
49static int
50my_getpagesize(void)
51{
Tim Peters5ebfd362001-11-13 23:11:19 +000052 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000053}
54#else
55#define my_getpagesize getpagesize
56#endif
57
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000058#endif /* UNIX */
59
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000060#include <string.h>
61#include <sys/types.h>
62
63static PyObject *mmap_module_error;
64
Tim Peters5ebfd362001-11-13 23:11:19 +000065typedef enum
66{
67 ACCESS_DEFAULT,
68 ACCESS_READ,
69 ACCESS_WRITE,
70 ACCESS_COPY
71} access_mode;
72
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000073typedef struct {
Guido van Rossum09fdf072000-03-31 01:17:07 +000074 PyObject_HEAD
75 char * data;
76 size_t size;
77 size_t pos;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000078
79#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +000080 HANDLE map_handle;
Mark Hammond071864a2000-07-30 02:46:26 +000081 HANDLE file_handle;
Guido van Rossum09fdf072000-03-31 01:17:07 +000082 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000083#endif
84
85#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000086 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000087#endif
Tim Peters5ebfd362001-11-13 23:11:19 +000088
89 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000090} mmap_object;
91
Tim Peters5ebfd362001-11-13 23:11:19 +000092
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000093static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +000094mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000095{
96#ifdef MS_WIN32
Mark Hammond2cbed002000-07-30 02:22:43 +000097 if (m_obj->data != NULL)
98 UnmapViewOfFile (m_obj->data);
99 if (m_obj->map_handle != INVALID_HANDLE_VALUE)
100 CloseHandle (m_obj->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000101 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
102 CloseHandle (m_obj->file_handle);
Mark Hammond2cbed002000-07-30 02:22:43 +0000103 if (m_obj->tagname)
104 PyMem_Free(m_obj->tagname);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000105#endif /* MS_WIN32 */
106
107#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000108 if (m_obj->data!=NULL) {
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000109 msync(m_obj->data, m_obj->size, MS_SYNC);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000110 munmap(m_obj->data, m_obj->size);
111 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000112#endif /* UNIX */
113
Guido van Rossumb18618d2000-05-03 23:44:39 +0000114 PyObject_Del(m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000115}
116
117static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000118mmap_close_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000119{
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000120 if (!PyArg_ParseTuple(args, ":close"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000121 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000122#ifdef MS_WIN32
Mark Hammond071864a2000-07-30 02:46:26 +0000123 /* For each resource we maintain, we need to check
124 the value is valid, and if so, free the resource
125 and set the member value to an invalid value so
126 the dealloc does not attempt to resource clearing
127 again.
128 TODO - should we check for errors in the close operations???
129 */
130 if (self->data != NULL) {
131 UnmapViewOfFile (self->data);
132 self->data = NULL;
133 }
134 if (self->map_handle != INVALID_HANDLE_VALUE) {
135 CloseHandle (self->map_handle);
136 self->map_handle = INVALID_HANDLE_VALUE;
137 }
138 if (self->file_handle != INVALID_HANDLE_VALUE) {
139 CloseHandle (self->file_handle);
140 self->file_handle = INVALID_HANDLE_VALUE;
141 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000142#endif /* MS_WIN32 */
143
144#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000145 munmap(self->data, self->size);
146 self->data = NULL;
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
153#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000154#define CHECK_VALID(err) \
155do { \
156 if (!self->map_handle) { \
157 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
158 return err; \
159 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000160} while (0)
161#endif /* MS_WIN32 */
162
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 p = self->data + start;
256
Guido van Rossum09fdf072000-03-31 01:17:07 +0000257 while (p < e) {
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000258 char *s = p;
259 char *n = needle;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000260 while ((s<e) && (*n) && !(*s-*n)) {
261 s++, n++;
262 }
263 if (!*n) {
264 return Py_BuildValue (
Tim Petersd401edd2001-05-14 23:19:12 +0000265 "l",
266 (long) (p - self->data));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000267 }
268 p++;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000269 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000270 return Py_BuildValue ("l", (long) -1);
271 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000272}
273
Tim Peters5ebfd362001-11-13 23:11:19 +0000274static int
275is_writeable(mmap_object *self)
276{
277 if (self->access != ACCESS_READ)
278 return 1;
279 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
280 return 0;
281}
282
283static int
284is_resizeable(mmap_object *self)
285{
286 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
287 return 1;
288 PyErr_Format(PyExc_TypeError,
289 "mmap can't resize a readonly or copy-on-write memory map.");
290 return 0;
291}
292
293
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000294static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000295mmap_write_method(mmap_object *self,
296 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000297{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000298 long length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000299 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000300
Guido van Rossum09fdf072000-03-31 01:17:07 +0000301 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000302 if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000303 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000304
Tim Peters5ebfd362001-11-13 23:11:19 +0000305 if (!is_writeable(self))
306 return NULL;
307
Guido van Rossum09fdf072000-03-31 01:17:07 +0000308 if ((self->pos + length) > self->size) {
309 PyErr_SetString (PyExc_ValueError, "data out of range");
310 return NULL;
311 }
312 memcpy (self->data+self->pos, data, length);
313 self->pos = self->pos+length;
314 Py_INCREF (Py_None);
315 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000316}
317
318static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000319mmap_write_byte_method(mmap_object *self,
320 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000321{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000322 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000323
Guido van Rossum09fdf072000-03-31 01:17:07 +0000324 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000325 if (!PyArg_ParseTuple (args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000326 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000327
Tim Peters5ebfd362001-11-13 23:11:19 +0000328 if (!is_writeable(self))
329 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000330 *(self->data+self->pos) = value;
331 self->pos += 1;
332 Py_INCREF (Py_None);
333 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000334}
Tim Peters5ebfd362001-11-13 23:11:19 +0000335
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000336static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000337mmap_size_method(mmap_object *self,
338 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000339{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000340 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000341 if (!PyArg_ParseTuple(args, ":size"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000342 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000343
344#ifdef MS_WIN32
Mark Hammond071864a2000-07-30 02:46:26 +0000345 if (self->file_handle != INVALID_HANDLE_VALUE) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000346 return (Py_BuildValue (
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000347 "l", (long)
Mark Hammond071864a2000-07-30 02:46:26 +0000348 GetFileSize (self->file_handle, NULL)));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000349 } else {
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000350 return (Py_BuildValue ("l", (long) self->size) );
Guido van Rossum09fdf072000-03-31 01:17:07 +0000351 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000352#endif /* MS_WIN32 */
353
354#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000355 {
356 struct stat buf;
357 if (-1 == fstat(self->fd, &buf)) {
358 PyErr_SetFromErrno(mmap_module_error);
359 return NULL;
360 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000361 return (Py_BuildValue ("l", (long) buf.st_size) );
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000362 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000363#endif /* UNIX */
364}
365
366/* This assumes that you want the entire file mapped,
367 / and when recreating the map will make the new file
368 / have the new size
369 /
370 / Is this really necessary? This could easily be done
371 / from python by just closing and re-opening with the
372 / new size?
373 */
374
375static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000376mmap_resize_method(mmap_object *self,
377 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000378{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000379 unsigned long new_size;
380 CHECK_VALID(NULL);
Tim Peters5ebfd362001-11-13 23:11:19 +0000381 if (!PyArg_ParseTuple (args, "l:resize", &new_size) ||
382 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000383 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000384#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000385 } else {
386 DWORD dwErrCode = 0;
387 /* First, unmap the file view */
388 UnmapViewOfFile (self->data);
389 /* Close the mapping object */
Mark Hammond071864a2000-07-30 02:46:26 +0000390 CloseHandle (self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000391 /* Move to the desired EOF position */
Mark Hammond071864a2000-07-30 02:46:26 +0000392 SetFilePointer (self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000393 new_size, NULL, FILE_BEGIN);
394 /* Change the size of the file */
Mark Hammond071864a2000-07-30 02:46:26 +0000395 SetEndOfFile (self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000396 /* Create another mapping object and remap the file view */
397 self->map_handle = CreateFileMapping (
Mark Hammond071864a2000-07-30 02:46:26 +0000398 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000399 NULL,
400 PAGE_READWRITE,
401 0,
402 new_size,
403 self->tagname);
404 if (self->map_handle != NULL) {
405 self->data = (char *) MapViewOfFile (self->map_handle,
406 FILE_MAP_WRITE,
407 0,
408 0,
409 0);
410 if (self->data != NULL) {
411 self->size = new_size;
412 Py_INCREF (Py_None);
413 return Py_None;
414 } else {
415 dwErrCode = GetLastError();
416 }
417 } else {
418 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000419 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000420 PyErr_SetFromWindowsErr(dwErrCode);
421 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000422#endif /* MS_WIN32 */
423
424#ifdef UNIX
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000425#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000426 } else {
427 PyErr_SetString(PyExc_SystemError,
428 "mmap: resizing not available--no mremap()");
429 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000430#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000431 } else {
432 void *newmap;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000433
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000434#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000435 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000436#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000437 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000438#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000439 if (newmap == (void *)-1)
440 {
441 PyErr_SetFromErrno(mmap_module_error);
442 return NULL;
443 }
444 self->data = newmap;
445 self->size = new_size;
446 Py_INCREF(Py_None);
447 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000448#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000449#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000450 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000451}
452
453static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000454mmap_tell_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000455{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000456 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000457 if (!PyArg_ParseTuple(args, ":tell"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000458 return NULL;
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000459 return (Py_BuildValue ("l", (long) self->pos) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000460}
461
462static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000463mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000464{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000465 size_t offset = 0;
466 size_t size = self->size;
467 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000468 if (!PyArg_ParseTuple (args, "|ll:flush", &offset, &size)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000469 return NULL;
470 } else if ((offset + size) > self->size) {
471 PyErr_SetString (PyExc_ValueError,
472 "flush values out of range");
473 return NULL;
474 } else {
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000475#ifdef MS_WIN32
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000476 return (Py_BuildValue("l", (long)
477 FlushViewOfFile(self->data+offset, size)));
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000478#endif /* MS_WIN32 */
479#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000480 /* XXX semantics of return value? */
481 /* XXX flags for msync? */
482 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000483 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000484 {
485 PyErr_SetFromErrno(mmap_module_error);
486 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000487 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000488 return Py_BuildValue ("l", (long) 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000489#endif /* UNIX */
490 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000491}
492
493static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000494mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000495{
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000496 int dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000497 int how=0;
498 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000499 if (!PyArg_ParseTuple (args, "i|i:seek", &dist, &how)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000500 return(NULL);
501 } else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000502 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000503 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000504 case 0: /* relative to start */
505 if (dist < 0)
506 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000507 where = dist;
508 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000509 case 1: /* relative to current position */
510 if ((int)self->pos + dist < 0)
511 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000512 where = self->pos + dist;
513 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000514 case 2: /* relative to end */
515 if ((int)self->size + dist < 0)
516 goto onoutofrange;
517 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000518 break;
519 default:
520 PyErr_SetString (PyExc_ValueError,
521 "unknown seek type");
522 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000523 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000524 if (where > self->size)
525 goto onoutofrange;
526 self->pos = where;
527 Py_INCREF (Py_None);
528 return (Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000529 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000530
Tim Peters5ebfd362001-11-13 23:11:19 +0000531 onoutofrange:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000532 PyErr_SetString (PyExc_ValueError, "seek out of range");
533 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000534}
535
536static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000537mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000538{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000539 unsigned long dest, src, count;
540 CHECK_VALID(NULL);
Tim Peters5ebfd362001-11-13 23:11:19 +0000541 if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count) ||
542 !is_writeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000543 return NULL;
544 } else {
545 /* bounds check the values */
546 if (/* end of source after end of data?? */
547 ((src+count) > self->size)
548 /* dest will fit? */
549 || (dest+count > self->size)) {
550 PyErr_SetString (PyExc_ValueError,
551 "source or destination out of range");
552 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000553 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000554 memmove (self->data+dest, self->data+src, count);
555 Py_INCREF (Py_None);
556 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000557 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000558 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000559}
560
561static struct PyMethodDef mmap_object_methods[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000562 {"close", (PyCFunction) mmap_close_method, 1},
563 {"find", (PyCFunction) mmap_find_method, 1},
564 {"flush", (PyCFunction) mmap_flush_method, 1},
565 {"move", (PyCFunction) mmap_move_method, 1},
566 {"read", (PyCFunction) mmap_read_method, 1},
567 {"read_byte", (PyCFunction) mmap_read_byte_method, 1},
568 {"readline", (PyCFunction) mmap_read_line_method, 1},
569 {"resize", (PyCFunction) mmap_resize_method, 1},
570 {"seek", (PyCFunction) mmap_seek_method, 1},
571 {"size", (PyCFunction) mmap_size_method, 1},
572 {"tell", (PyCFunction) mmap_tell_method, 1},
573 {"write", (PyCFunction) mmap_write_method, 1},
574 {"write_byte", (PyCFunction) mmap_write_byte_method, 1},
575 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000576};
577
578/* Functions for treating an mmap'ed file as a buffer */
579
580static int
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000581mmap_buffer_getreadbuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000582{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000583 CHECK_VALID(-1);
584 if ( index != 0 ) {
585 PyErr_SetString(PyExc_SystemError,
586 "Accessing non-existent mmap segment");
587 return -1;
588 }
589 *ptr = self->data;
590 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000591}
592
593static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000594mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000595{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000596 CHECK_VALID(-1);
597 if ( index != 0 ) {
598 PyErr_SetString(PyExc_SystemError,
599 "Accessing non-existent mmap segment");
600 return -1;
601 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000602 if (!is_writeable(self))
603 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000604 *ptr = self->data;
605 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000606}
607
608static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000609mmap_buffer_getsegcount(mmap_object *self, int *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000610{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000611 CHECK_VALID(-1);
612 if (lenp)
613 *lenp = self->size;
614 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000615}
616
617static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000618mmap_buffer_getcharbuffer(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000619{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000620 if ( index != 0 ) {
621 PyErr_SetString(PyExc_SystemError,
622 "accessing non-existent buffer segment");
623 return -1;
624 }
625 *ptr = (const char *)self->data;
626 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000627}
628
629static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000630mmap_object_getattr(mmap_object *self, char *name)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000631{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000632 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000633}
634
635static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000636mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000637{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000638 CHECK_VALID(-1);
639 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000640}
641
642static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000643mmap_item(mmap_object *self, int i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000644{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000645 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000646 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000647 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
648 return NULL;
649 }
650 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000651}
652
653static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000654mmap_slice(mmap_object *self, int ilow, int ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000655{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000656 CHECK_VALID(NULL);
657 if (ilow < 0)
658 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000659 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000660 ilow = self->size;
661 if (ihigh < 0)
662 ihigh = 0;
663 if (ihigh < ilow)
664 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000665 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000666 ihigh = self->size;
667
668 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000669}
670
671static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000672mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000673{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000674 CHECK_VALID(NULL);
675 PyErr_SetString(PyExc_SystemError,
676 "mmaps don't support concatenation");
677 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000678}
679
680static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000681mmap_repeat(mmap_object *self, int n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000682{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000683 CHECK_VALID(NULL);
684 PyErr_SetString(PyExc_SystemError,
685 "mmaps don't support repeat operation");
686 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000687}
688
689static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000690mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000691{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000692 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000693
Guido van Rossum09fdf072000-03-31 01:17:07 +0000694 CHECK_VALID(-1);
695 if (ilow < 0)
696 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000697 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000698 ilow = self->size;
699 if (ihigh < 0)
700 ihigh = 0;
701 if (ihigh < ilow)
702 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000703 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000704 ihigh = self->size;
705
Thomas Wouters1baac722001-07-16 15:47:36 +0000706 if (v == NULL) {
707 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000708 "mmap object doesn't support slice deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000709 return -1;
710 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000711 if (! (PyString_Check(v)) ) {
712 PyErr_SetString(PyExc_IndexError,
713 "mmap slice assignment must be a string");
714 return -1;
715 }
716 if ( PyString_Size(v) != (ihigh - ilow) ) {
717 PyErr_SetString(PyExc_IndexError,
718 "mmap slice assignment is wrong size");
719 return -1;
720 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000721 if (!is_writeable(self))
722 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000723 buf = PyString_AsString(v);
724 memcpy(self->data + ilow, buf, ihigh-ilow);
725 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000726}
727
728static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000729mmap_ass_item(mmap_object *self, int i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000730{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000731 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000732
Guido van Rossum09fdf072000-03-31 01:17:07 +0000733 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000734 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000735 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
736 return -1;
737 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000738 if (v == NULL) {
739 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000740 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000741 return -1;
742 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000743 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
744 PyErr_SetString(PyExc_IndexError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000745 "mmap assignment must be single-character string");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000746 return -1;
747 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000748 if (!is_writeable(self))
749 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000750 buf = PyString_AsString(v);
751 self->data[i] = buf[0];
752 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000753}
754
755static PySequenceMethods mmap_as_sequence = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000756 (inquiry)mmap_length, /*sq_length*/
757 (binaryfunc)mmap_concat, /*sq_concat*/
758 (intargfunc)mmap_repeat, /*sq_repeat*/
759 (intargfunc)mmap_item, /*sq_item*/
760 (intintargfunc)mmap_slice, /*sq_slice*/
761 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
762 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000763};
764
765static PyBufferProcs mmap_as_buffer = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000766 (getreadbufferproc)mmap_buffer_getreadbuf,
767 (getwritebufferproc)mmap_buffer_getwritebuf,
768 (getsegcountproc)mmap_buffer_getsegcount,
769 (getcharbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000770};
771
772static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000773 PyObject_HEAD_INIT(0) /* patched in module init */
774 0, /* ob_size */
775 "mmap", /* tp_name */
776 sizeof(mmap_object), /* tp_size */
777 0, /* tp_itemsize */
778 /* methods */
779 (destructor) mmap_object_dealloc, /* tp_dealloc */
780 0, /* tp_print */
781 (getattrfunc) mmap_object_getattr, /* tp_getattr */
782 0, /* tp_setattr */
783 0, /* tp_compare */
784 0, /* tp_repr */
785 0, /* tp_as_number */
786 &mmap_as_sequence, /*tp_as_sequence*/
787 0, /*tp_as_mapping*/
788 0, /*tp_hash*/
789 0, /*tp_call*/
790 0, /*tp_str*/
791 0, /*tp_getattro*/
792 0, /*tp_setattro*/
793 &mmap_as_buffer, /*tp_as_buffer*/
794 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
795 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000796};
797
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000798
799/* extract the map size from the given PyObject
800
801 The map size is restricted to [0, INT_MAX] because this is the current
802 Python limitation on object sizes. Although the mmap object *could* handle
803 a larger map size, there is no point because all the useful operations
804 (len(), slicing(), sequence indexing) are limited by a C int.
805
Thomas Wouters7e474022000-07-16 12:04:32 +0000806 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000807 success, the map size is returned. */
808static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000809_GetMapSize(PyObject *o)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000810{
811 if (PyInt_Check(o)) {
812 long i = PyInt_AsLong(o);
813 if (PyErr_Occurred())
814 return -1;
815 if (i < 0)
816 goto onnegoverflow;
817 if (i > INT_MAX)
818 goto onposoverflow;
819 return (int)i;
820 }
821 else if (PyLong_Check(o)) {
822 long i = PyLong_AsLong(o);
823 if (PyErr_Occurred()) {
824 /* yes negative overflow is mistaken for positive overflow
825 but not worth the trouble to check sign of 'i' */
826 if (PyErr_ExceptionMatches(PyExc_OverflowError))
827 goto onposoverflow;
828 else
829 return -1;
830 }
831 if (i < 0)
832 goto onnegoverflow;
833 if (i > INT_MAX)
834 goto onposoverflow;
835 return (int)i;
836 }
837 else {
838 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000839 "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000840 return -1;
841 }
842
Tim Peters5ebfd362001-11-13 23:11:19 +0000843 onnegoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000844 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000845 "memory mapped size must be positive");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000846 return -1;
847
Tim Peters5ebfd362001-11-13 23:11:19 +0000848 onposoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000849 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000850 "memory mapped size is too large (limited by C int)");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000851 return -1;
852}
853
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000854#ifdef UNIX
855static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000856new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000857{
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 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000898
Guido van Rossumb18618d2000-05-03 23:44:39 +0000899 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000900 if (m_obj == NULL) {return NULL;}
901 m_obj->size = (size_t) map_size;
902 m_obj->pos = (size_t) 0;
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000903 m_obj->fd = fd;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000904 m_obj->data = mmap(NULL, map_size,
905 prot, flags,
906 fd, 0);
Tim Peters5ebfd362001-11-13 23:11:19 +0000907 if (m_obj->data == (char *)-1) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000908 Py_DECREF(m_obj);
909 PyErr_SetFromErrno(mmap_module_error);
910 return NULL;
911 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000912 m_obj->access = access;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000913 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000914}
915#endif /* UNIX */
916
917#ifdef MS_WIN32
918static PyObject *
Tim Peters5ebfd362001-11-13 23:11:19 +0000919new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000920{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000921 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000922 PyObject *map_size_obj = NULL;
923 int map_size;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000924 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +0000925 DWORD dwErr = 0;
926 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +0000927 HANDLE fh = 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000928 access_mode access = ACCESS_DEFAULT;
929 DWORD flProtect, dwDesiredAccess;
930 char *keywords[] = { "fileno", "length",
931 "tagname",
932 "access", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000933
Tim Peters5ebfd362001-11-13 23:11:19 +0000934 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|zi", keywords,
935 &fileno, &map_size_obj,
936 &tagname, &access)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000937 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000938 }
939
940 switch(access) {
941 case ACCESS_READ:
942 flProtect = PAGE_READONLY;
943 dwDesiredAccess = FILE_MAP_READ;
944 break;
945 case ACCESS_DEFAULT: case ACCESS_WRITE:
946 flProtect = PAGE_READWRITE;
947 dwDesiredAccess = FILE_MAP_WRITE;
948 break;
949 case ACCESS_COPY:
950 flProtect = PAGE_WRITECOPY;
951 dwDesiredAccess = FILE_MAP_COPY;
952 break;
953 default:
954 return PyErr_Format(PyExc_ValueError,
955 "mmap invalid access parameter.");
956 }
957
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000958 map_size = _GetMapSize(map_size_obj);
959 if (map_size < 0)
960 return NULL;
961
Guido van Rossum09fdf072000-03-31 01:17:07 +0000962 /* if an actual filename has been specified */
963 if (fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +0000964 fh = (HANDLE)_get_osfhandle(fileno);
965 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +0000966 PyErr_SetFromErrno(mmap_module_error);
967 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000968 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +0000969 /* Win9x appears to need us seeked to zero */
970 fseek(&_iob[fileno], 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000971 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000972
Guido van Rossumb18618d2000-05-03 23:44:39 +0000973 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Mark Hammond2cbed002000-07-30 02:22:43 +0000974 if (m_obj==NULL)
975 return NULL;
976 /* Set every field to an invalid marker, so we can safely
977 destruct the object in the face of failure */
978 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +0000979 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +0000980 m_obj->map_handle = INVALID_HANDLE_VALUE;
981 m_obj->tagname = NULL;
982
Guido van Rossum09fdf072000-03-31 01:17:07 +0000983 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +0000984 /* It is necessary to duplicate the handle, so the
985 Python code can close it on us */
986 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +0000987 GetCurrentProcess(), /* source process handle */
988 fh, /* handle to be duplicated */
989 GetCurrentProcess(), /* target proc handle */
990 (LPHANDLE)&m_obj->file_handle, /* result */
991 0, /* access - ignored due to options value */
992 FALSE, /* inherited by child processes? */
993 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +0000994 dwErr = GetLastError();
995 Py_DECREF(m_obj);
996 PyErr_SetFromWindowsErr(dwErr);
997 return NULL;
998 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000999 if (!map_size) {
Mark Hammond071864a2000-07-30 02:46:26 +00001000 m_obj->size = GetFileSize (fh, NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001001 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001002 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001003 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001004 }
1005 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001006 m_obj->size = map_size;
1007 }
1008
1009 /* set the initial position */
1010 m_obj->pos = (size_t) 0;
1011
Mark Hammond2cbed002000-07-30 02:22:43 +00001012 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001013 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001014 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1015 if (m_obj->tagname == NULL) {
1016 PyErr_NoMemory();
1017 Py_DECREF(m_obj);
1018 return NULL;
1019 }
1020 strcpy(m_obj->tagname, tagname);
1021 }
1022 else
1023 m_obj->tagname = NULL;
1024
Tim Peters5ebfd362001-11-13 23:11:19 +00001025 m_obj->access = access;
Mark Hammond071864a2000-07-30 02:46:26 +00001026 m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001027 NULL,
Tim Peters5ebfd362001-11-13 23:11:19 +00001028 flProtect,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001029 0,
1030 m_obj->size,
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001031 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001032 if (m_obj->map_handle != NULL) {
1033 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
Tim Peters5ebfd362001-11-13 23:11:19 +00001034 dwDesiredAccess,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001035 0,
1036 0,
1037 0);
1038 if (m_obj->data != NULL) {
1039 return ((PyObject *) m_obj);
1040 } else {
Tim Peters5ebfd362001-11-13 23:11:19 +00001041 dwErr = GetLastError();
Guido van Rossum09fdf072000-03-31 01:17:07 +00001042 }
1043 } else {
1044 dwErr = GetLastError();
1045 }
Mark Hammond2cbed002000-07-30 02:22:43 +00001046 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001047 PyErr_SetFromWindowsErr(dwErr);
1048 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001049}
1050#endif /* MS_WIN32 */
1051
1052/* List of functions exported by this module */
1053static struct PyMethodDef mmap_functions[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001054 {"mmap", (PyCFunction) new_mmap_object,
1055 METH_VARARGS|METH_KEYWORDS},
1056 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001057};
1058
Guido van Rossum5a530192001-01-10 21:03:32 +00001059DL_EXPORT(void)
Tim Peters5ebfd362001-11-13 23:11:19 +00001060 initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001061{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001062 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001063
1064 /* Patch the object type */
1065 mmap_object_type.ob_type = &PyType_Type;
1066
Guido van Rossum09fdf072000-03-31 01:17:07 +00001067 module = Py_InitModule ("mmap", mmap_functions);
1068 dict = PyModule_GetDict (module);
1069 mmap_module_error = PyExc_EnvironmentError;
1070 Py_INCREF(mmap_module_error);
1071 PyDict_SetItemString (dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001072#ifdef PROT_EXEC
Guido van Rossum09fdf072000-03-31 01:17:07 +00001073 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001074#endif
1075#ifdef PROT_READ
Guido van Rossum09fdf072000-03-31 01:17:07 +00001076 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001077#endif
1078#ifdef PROT_WRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001079 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001080#endif
1081
1082#ifdef MAP_SHARED
Guido van Rossum09fdf072000-03-31 01:17:07 +00001083 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001084#endif
1085#ifdef MAP_PRIVATE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001086 PyDict_SetItemString (dict, "MAP_PRIVATE",
1087 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001088#endif
1089#ifdef MAP_DENYWRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001090 PyDict_SetItemString (dict, "MAP_DENYWRITE",
1091 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001092#endif
1093#ifdef MAP_EXECUTABLE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001094 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
1095 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001096#endif
1097#ifdef MAP_ANON
Guido van Rossum09fdf072000-03-31 01:17:07 +00001098 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
1099 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
1100 PyInt_FromLong(MAP_ANON) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001101#endif
1102
Guido van Rossum09fdf072000-03-31 01:17:07 +00001103 PyDict_SetItemString (dict, "PAGESIZE",
Fred Drake145f96e2000-10-01 17:50:46 +00001104 PyInt_FromLong( (long)my_getpagesize() ) );
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001105
Tim Peters5ebfd362001-11-13 23:11:19 +00001106 PyDict_SetItemString (dict, "ACCESS_READ",
1107 PyInt_FromLong(ACCESS_READ));
1108 PyDict_SetItemString (dict, "ACCESS_WRITE",
1109 PyInt_FromLong(ACCESS_WRITE));
1110 PyDict_SetItemString (dict, "ACCESS_COPY",
1111 PyInt_FromLong(ACCESS_COPY));
1112}