Apparently the code to forestall Tk eating events was too aggressive (Tk user input...
[python/dscho.git] / Modules / mmapmodule.c
blobc48278f6c553eb5ec3ed6f50390e129c270cda65
1 /*
2 / Author: Sam Rushing <rushing@nightmare.com>
3 / Hacked for Unix by A.M. Kuchling <amk1@bigfoot.com>
4 / $Id$
6 / mmapmodule.cpp -- map a view of a file into memory
8 / todo: need permission flags, perhaps a 'chsize' analog
9 / not all functions check range yet!!!
12 / Note: This module currently only deals with 32-bit file
13 / sizes.
15 / 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
18 / ftp://squirl.nightmare.com/pub/python/python-ext.
21 #include <Python.h>
23 #ifndef MS_WIN32
24 #define UNIX
25 #endif
27 #ifdef MS_WIN32
28 #include <windows.h>
29 static int
30 my_getpagesize(void)
32 SYSTEM_INFO si;
33 GetSystemInfo(&si);
34 return si.dwPageSize;
36 #endif
38 #ifdef UNIX
39 #include <unistd.h>
40 #include <sys/mman.h>
41 #include <sys/stat.h>
43 #ifndef MS_SYNC
44 /* This is missing e.g. on SunOS 4.1.4 */
45 #define MS_SYNC 0
46 #endif
48 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
49 static int
50 my_getpagesize(void)
52 return sysconf(_SC_PAGESIZE);
54 #else
55 #define my_getpagesize getpagesize
56 #endif
58 #endif /* UNIX */
60 #include <string.h>
61 #include <sys/types.h>
63 static PyObject *mmap_module_error;
65 typedef struct {
66 PyObject_HEAD
67 char * data;
68 size_t size;
69 size_t pos;
71 #ifdef MS_WIN32
72 HANDLE map_handle;
73 HANDLE file_handle;
74 char * tagname;
75 #endif
77 #ifdef UNIX
78 int fd;
79 #endif
80 } mmap_object;
82 static void
83 mmap_object_dealloc(mmap_object *m_obj)
85 #ifdef MS_WIN32
86 if (m_obj->data != NULL)
87 UnmapViewOfFile (m_obj->data);
88 if (m_obj->map_handle != INVALID_HANDLE_VALUE)
89 CloseHandle (m_obj->map_handle);
90 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
91 CloseHandle (m_obj->file_handle);
92 if (m_obj->tagname)
93 PyMem_Free(m_obj->tagname);
94 #endif /* MS_WIN32 */
96 #ifdef UNIX
97 if (m_obj->data!=NULL) {
98 msync(m_obj->data, m_obj->size, MS_SYNC);
99 munmap(m_obj->data, m_obj->size);
101 #endif /* UNIX */
103 PyObject_Del(m_obj);
106 static PyObject *
107 mmap_close_method(mmap_object *self, PyObject *args)
109 if (!PyArg_ParseTuple(args, ":close"))
110 return NULL;
111 #ifdef MS_WIN32
112 /* For each resource we maintain, we need to check
113 the value is valid, and if so, free the resource
114 and set the member value to an invalid value so
115 the dealloc does not attempt to resource clearing
116 again.
117 TODO - should we check for errors in the close operations???
119 if (self->data != NULL) {
120 UnmapViewOfFile (self->data);
121 self->data = NULL;
123 if (self->map_handle != INVALID_HANDLE_VALUE) {
124 CloseHandle (self->map_handle);
125 self->map_handle = INVALID_HANDLE_VALUE;
127 if (self->file_handle != INVALID_HANDLE_VALUE) {
128 CloseHandle (self->file_handle);
129 self->file_handle = INVALID_HANDLE_VALUE;
131 #endif /* MS_WIN32 */
133 #ifdef UNIX
134 munmap(self->data, self->size);
135 self->data = NULL;
136 #endif
138 Py_INCREF (Py_None);
139 return (Py_None);
142 #ifdef MS_WIN32
143 #define CHECK_VALID(err) \
144 do { \
145 if (!self->map_handle) { \
146 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
147 return err; \
149 } while (0)
150 #endif /* MS_WIN32 */
152 #ifdef UNIX
153 #define CHECK_VALID(err) \
154 do { \
155 if (self->data == NULL) { \
156 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
157 return err; \
159 } while (0)
160 #endif /* UNIX */
162 static PyObject *
163 mmap_read_byte_method(mmap_object *self,
164 PyObject *args)
166 char value;
167 char *where;
168 CHECK_VALID(NULL);
169 if (!PyArg_ParseTuple(args, ":read_byte"))
170 return NULL;
171 if (self->pos < self->size) {
172 where = self->data + self->pos;
173 value = (char) *(where);
174 self->pos += 1;
175 return Py_BuildValue("c", (char) *(where));
176 } else {
177 PyErr_SetString (PyExc_ValueError, "read byte out of range");
178 return NULL;
182 static PyObject *
183 mmap_read_line_method(mmap_object *self,
184 PyObject *args)
186 char *start = self->data+self->pos;
187 char *eof = self->data+self->size;
188 char *eol;
189 PyObject *result;
191 CHECK_VALID(NULL);
192 if (!PyArg_ParseTuple(args, ":readline"))
193 return NULL;
195 eol = memchr(start, '\n', self->size - self->pos);
196 if (!eol)
197 eol = eof;
198 else
199 ++eol; /* we're interested in the position after the
200 newline. */
201 result = PyString_FromStringAndSize(start, (eol - start));
202 self->pos += (eol - start);
203 return (result);
206 static PyObject *
207 mmap_read_method(mmap_object *self,
208 PyObject *args)
210 long num_bytes;
211 PyObject *result;
213 CHECK_VALID(NULL);
214 if (!PyArg_ParseTuple(args, "l:read", &num_bytes))
215 return(NULL);
217 /* silently 'adjust' out-of-range requests */
218 if ((self->pos + num_bytes) > self->size) {
219 num_bytes -= (self->pos+num_bytes) - self->size;
221 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
222 self->pos += num_bytes;
223 return (result);
226 static PyObject *
227 mmap_find_method(mmap_object *self,
228 PyObject *args)
230 int start = self->pos;
231 char *needle;
232 int len;
234 CHECK_VALID(NULL);
235 if (!PyArg_ParseTuple (args, "s#|i:find", &needle, &len, &start)) {
236 return NULL;
237 } else {
238 char *p = self->data+self->pos;
239 char *e = self->data+self->size;
240 while (p < e) {
241 char *s = p;
242 char *n = needle;
243 while ((s<e) && (*n) && !(*s-*n)) {
244 s++, n++;
246 if (!*n) {
247 return Py_BuildValue (
248 "i",
249 (int) (p - (self->data + start)));
251 p++;
253 return Py_BuildValue ("l", (long) -1);
257 static PyObject *
258 mmap_write_method(mmap_object *self,
259 PyObject *args)
261 long length;
262 char *data;
264 CHECK_VALID(NULL);
265 if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
266 return(NULL);
268 if ((self->pos + length) > self->size) {
269 PyErr_SetString (PyExc_ValueError, "data out of range");
270 return NULL;
272 memcpy (self->data+self->pos, data, length);
273 self->pos = self->pos+length;
274 Py_INCREF (Py_None);
275 return (Py_None);
278 static PyObject *
279 mmap_write_byte_method(mmap_object *self,
280 PyObject *args)
282 char value;
284 CHECK_VALID(NULL);
285 if (!PyArg_ParseTuple (args, "c:write_byte", &value))
286 return(NULL);
288 *(self->data+self->pos) = value;
289 self->pos += 1;
290 Py_INCREF (Py_None);
291 return (Py_None);
294 static PyObject *
295 mmap_size_method(mmap_object *self,
296 PyObject *args)
298 CHECK_VALID(NULL);
299 if (!PyArg_ParseTuple(args, ":size"))
300 return NULL;
302 #ifdef MS_WIN32
303 if (self->file_handle != INVALID_HANDLE_VALUE) {
304 return (Py_BuildValue (
305 "l", (long)
306 GetFileSize (self->file_handle, NULL)));
307 } else {
308 return (Py_BuildValue ("l", (long) self->size) );
310 #endif /* MS_WIN32 */
312 #ifdef UNIX
314 struct stat buf;
315 if (-1 == fstat(self->fd, &buf)) {
316 PyErr_SetFromErrno(mmap_module_error);
317 return NULL;
319 return (Py_BuildValue ("l", (long) buf.st_size) );
321 #endif /* UNIX */
324 /* This assumes that you want the entire file mapped,
325 / and when recreating the map will make the new file
326 / have the new size
328 / Is this really necessary? This could easily be done
329 / from python by just closing and re-opening with the
330 / new size?
333 static PyObject *
334 mmap_resize_method(mmap_object *self,
335 PyObject *args)
337 unsigned long new_size;
338 CHECK_VALID(NULL);
339 if (!PyArg_ParseTuple (args, "l:resize", &new_size)) {
340 return NULL;
341 #ifdef MS_WIN32
342 } else {
343 DWORD dwErrCode = 0;
344 /* First, unmap the file view */
345 UnmapViewOfFile (self->data);
346 /* Close the mapping object */
347 CloseHandle (self->map_handle);
348 /* Move to the desired EOF position */
349 SetFilePointer (self->file_handle,
350 new_size, NULL, FILE_BEGIN);
351 /* Change the size of the file */
352 SetEndOfFile (self->file_handle);
353 /* Create another mapping object and remap the file view */
354 self->map_handle = CreateFileMapping (
355 self->file_handle,
356 NULL,
357 PAGE_READWRITE,
359 new_size,
360 self->tagname);
361 if (self->map_handle != NULL) {
362 self->data = (char *) MapViewOfFile (self->map_handle,
363 FILE_MAP_WRITE,
367 if (self->data != NULL) {
368 self->size = new_size;
369 Py_INCREF (Py_None);
370 return Py_None;
371 } else {
372 dwErrCode = GetLastError();
374 } else {
375 dwErrCode = GetLastError();
377 PyErr_SetFromWindowsErr(dwErrCode);
378 return (NULL);
379 #endif /* MS_WIN32 */
381 #ifdef UNIX
382 #ifndef HAVE_MREMAP
383 } else {
384 PyErr_SetString(PyExc_SystemError,
385 "mmap: resizing not available--no mremap()");
386 return NULL;
387 #else
388 } else {
389 void *newmap;
391 #ifdef MREMAP_MAYMOVE
392 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
393 #else
394 newmap = mremap(self->data, self->size, new_size, 0);
395 #endif
396 if (newmap == (void *)-1)
398 PyErr_SetFromErrno(mmap_module_error);
399 return NULL;
401 self->data = newmap;
402 self->size = new_size;
403 Py_INCREF(Py_None);
404 return Py_None;
405 #endif /* HAVE_MREMAP */
406 #endif /* UNIX */
410 static PyObject *
411 mmap_tell_method(mmap_object *self, PyObject *args)
413 CHECK_VALID(NULL);
414 if (!PyArg_ParseTuple(args, ":tell"))
415 return NULL;
416 return (Py_BuildValue ("l", (long) self->pos) );
419 static PyObject *
420 mmap_flush_method(mmap_object *self, PyObject *args)
422 size_t offset = 0;
423 size_t size = self->size;
424 CHECK_VALID(NULL);
425 if (!PyArg_ParseTuple (args, "|ll:flush", &offset, &size)) {
426 return NULL;
427 } else if ((offset + size) > self->size) {
428 PyErr_SetString (PyExc_ValueError,
429 "flush values out of range");
430 return NULL;
431 } else {
432 #ifdef MS_WIN32
433 return (Py_BuildValue("l", (long)
434 FlushViewOfFile(self->data+offset, size)));
435 #endif /* MS_WIN32 */
436 #ifdef UNIX
437 /* XXX semantics of return value? */
438 /* XXX flags for msync? */
439 if (-1 == msync(self->data + offset, size,
440 MS_SYNC))
442 PyErr_SetFromErrno(mmap_module_error);
443 return NULL;
445 return Py_BuildValue ("l", (long) 0);
446 #endif /* UNIX */
450 static PyObject *
451 mmap_seek_method(mmap_object *self, PyObject *args)
453 int dist;
454 int how=0;
455 CHECK_VALID(NULL);
456 if (!PyArg_ParseTuple (args, "i|i:seek", &dist, &how)) {
457 return(NULL);
458 } else {
459 size_t where;
460 switch (how) {
461 case 0: /* relative to start */
462 if (dist < 0)
463 goto onoutofrange;
464 where = dist;
465 break;
466 case 1: /* relative to current position */
467 if ((int)self->pos + dist < 0)
468 goto onoutofrange;
469 where = self->pos + dist;
470 break;
471 case 2: /* relative to end */
472 if ((int)self->size + dist < 0)
473 goto onoutofrange;
474 where = self->size + dist;
475 break;
476 default:
477 PyErr_SetString (PyExc_ValueError,
478 "unknown seek type");
479 return NULL;
481 if (where > self->size)
482 goto onoutofrange;
483 self->pos = where;
484 Py_INCREF (Py_None);
485 return (Py_None);
488 onoutofrange:
489 PyErr_SetString (PyExc_ValueError, "seek out of range");
490 return NULL;
493 static PyObject *
494 mmap_move_method(mmap_object *self, PyObject *args)
496 unsigned long dest, src, count;
497 CHECK_VALID(NULL);
498 if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count)) {
499 return NULL;
500 } else {
501 /* bounds check the values */
502 if (/* end of source after end of data?? */
503 ((src+count) > self->size)
504 /* dest will fit? */
505 || (dest+count > self->size)) {
506 PyErr_SetString (PyExc_ValueError,
507 "source or destination out of range");
508 return NULL;
509 } else {
510 memmove (self->data+dest, self->data+src, count);
511 Py_INCREF (Py_None);
512 return Py_None;
517 static struct PyMethodDef mmap_object_methods[] = {
518 {"close", (PyCFunction) mmap_close_method, 1},
519 {"find", (PyCFunction) mmap_find_method, 1},
520 {"flush", (PyCFunction) mmap_flush_method, 1},
521 {"move", (PyCFunction) mmap_move_method, 1},
522 {"read", (PyCFunction) mmap_read_method, 1},
523 {"read_byte", (PyCFunction) mmap_read_byte_method, 1},
524 {"readline", (PyCFunction) mmap_read_line_method, 1},
525 {"resize", (PyCFunction) mmap_resize_method, 1},
526 {"seek", (PyCFunction) mmap_seek_method, 1},
527 {"size", (PyCFunction) mmap_size_method, 1},
528 {"tell", (PyCFunction) mmap_tell_method, 1},
529 {"write", (PyCFunction) mmap_write_method, 1},
530 {"write_byte", (PyCFunction) mmap_write_byte_method, 1},
531 {NULL, NULL} /* sentinel */
534 /* Functions for treating an mmap'ed file as a buffer */
536 static int
537 mmap_buffer_getreadbuf(mmap_object *self, int index, const void **ptr)
539 CHECK_VALID(-1);
540 if ( index != 0 ) {
541 PyErr_SetString(PyExc_SystemError,
542 "Accessing non-existent mmap segment");
543 return -1;
545 *ptr = self->data;
546 return self->size;
549 static int
550 mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
552 CHECK_VALID(-1);
553 if ( index != 0 ) {
554 PyErr_SetString(PyExc_SystemError,
555 "Accessing non-existent mmap segment");
556 return -1;
558 *ptr = self->data;
559 return self->size;
562 static int
563 mmap_buffer_getsegcount(mmap_object *self, int *lenp)
565 CHECK_VALID(-1);
566 if (lenp)
567 *lenp = self->size;
568 return 1;
571 static int
572 mmap_buffer_getcharbuffer(mmap_object *self, int index, const void **ptr)
574 if ( index != 0 ) {
575 PyErr_SetString(PyExc_SystemError,
576 "accessing non-existent buffer segment");
577 return -1;
579 *ptr = (const char *)self->data;
580 return self->size;
583 static PyObject *
584 mmap_object_getattr(mmap_object *self, char *name)
586 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
589 static int
590 mmap_length(mmap_object *self)
592 CHECK_VALID(-1);
593 return self->size;
596 static PyObject *
597 mmap_item(mmap_object *self, int i)
599 CHECK_VALID(NULL);
600 if (i < 0 || (size_t)i >= self->size) {
601 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
602 return NULL;
604 return PyString_FromStringAndSize(self->data + i, 1);
607 static PyObject *
608 mmap_slice(mmap_object *self, int ilow, int ihigh)
610 CHECK_VALID(NULL);
611 if (ilow < 0)
612 ilow = 0;
613 else if ((size_t)ilow > self->size)
614 ilow = self->size;
615 if (ihigh < 0)
616 ihigh = 0;
617 if (ihigh < ilow)
618 ihigh = ilow;
619 else if ((size_t)ihigh > self->size)
620 ihigh = self->size;
622 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
625 static PyObject *
626 mmap_concat(mmap_object *self, PyObject *bb)
628 CHECK_VALID(NULL);
629 PyErr_SetString(PyExc_SystemError,
630 "mmaps don't support concatenation");
631 return NULL;
634 static PyObject *
635 mmap_repeat(mmap_object *self, int n)
637 CHECK_VALID(NULL);
638 PyErr_SetString(PyExc_SystemError,
639 "mmaps don't support repeat operation");
640 return NULL;
643 static int
644 mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
646 const char *buf;
648 CHECK_VALID(-1);
649 if (ilow < 0)
650 ilow = 0;
651 else if ((size_t)ilow > self->size)
652 ilow = self->size;
653 if (ihigh < 0)
654 ihigh = 0;
655 if (ihigh < ilow)
656 ihigh = ilow;
657 else if ((size_t)ihigh > self->size)
658 ihigh = self->size;
660 if (! (PyString_Check(v)) ) {
661 PyErr_SetString(PyExc_IndexError,
662 "mmap slice assignment must be a string");
663 return -1;
665 if ( PyString_Size(v) != (ihigh - ilow) ) {
666 PyErr_SetString(PyExc_IndexError,
667 "mmap slice assignment is wrong size");
668 return -1;
670 buf = PyString_AsString(v);
671 memcpy(self->data + ilow, buf, ihigh-ilow);
672 return 0;
675 static int
676 mmap_ass_item(mmap_object *self, int i, PyObject *v)
678 const char *buf;
680 CHECK_VALID(-1);
681 if (i < 0 || (size_t)i >= self->size) {
682 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
683 return -1;
685 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
686 PyErr_SetString(PyExc_IndexError,
687 "mmap assignment must be single-character string");
688 return -1;
690 buf = PyString_AsString(v);
691 self->data[i] = buf[0];
692 return 0;
695 static PySequenceMethods mmap_as_sequence = {
696 (inquiry)mmap_length, /*sq_length*/
697 (binaryfunc)mmap_concat, /*sq_concat*/
698 (intargfunc)mmap_repeat, /*sq_repeat*/
699 (intargfunc)mmap_item, /*sq_item*/
700 (intintargfunc)mmap_slice, /*sq_slice*/
701 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
702 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
705 static PyBufferProcs mmap_as_buffer = {
706 (getreadbufferproc)mmap_buffer_getreadbuf,
707 (getwritebufferproc)mmap_buffer_getwritebuf,
708 (getsegcountproc)mmap_buffer_getsegcount,
709 (getcharbufferproc)mmap_buffer_getcharbuffer,
712 static PyTypeObject mmap_object_type = {
713 PyObject_HEAD_INIT(0) /* patched in module init */
714 0, /* ob_size */
715 "mmap", /* tp_name */
716 sizeof(mmap_object), /* tp_size */
717 0, /* tp_itemsize */
718 /* methods */
719 (destructor) mmap_object_dealloc, /* tp_dealloc */
720 0, /* tp_print */
721 (getattrfunc) mmap_object_getattr, /* tp_getattr */
722 0, /* tp_setattr */
723 0, /* tp_compare */
724 0, /* tp_repr */
725 0, /* tp_as_number */
726 &mmap_as_sequence, /*tp_as_sequence*/
727 0, /*tp_as_mapping*/
728 0, /*tp_hash*/
729 0, /*tp_call*/
730 0, /*tp_str*/
731 0, /*tp_getattro*/
732 0, /*tp_setattro*/
733 &mmap_as_buffer, /*tp_as_buffer*/
734 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
735 0, /*tp_doc*/
739 /* extract the map size from the given PyObject
741 The map size is restricted to [0, INT_MAX] because this is the current
742 Python limitation on object sizes. Although the mmap object *could* handle
743 a larger map size, there is no point because all the useful operations
744 (len(), slicing(), sequence indexing) are limited by a C int.
746 Returns -1 on error, with an appropriate Python exception raised. On
747 success, the map size is returned. */
748 static int
749 _GetMapSize(PyObject *o)
751 if (PyInt_Check(o)) {
752 long i = PyInt_AsLong(o);
753 if (PyErr_Occurred())
754 return -1;
755 if (i < 0)
756 goto onnegoverflow;
757 if (i > INT_MAX)
758 goto onposoverflow;
759 return (int)i;
761 else if (PyLong_Check(o)) {
762 long i = PyLong_AsLong(o);
763 if (PyErr_Occurred()) {
764 /* yes negative overflow is mistaken for positive overflow
765 but not worth the trouble to check sign of 'i' */
766 if (PyErr_ExceptionMatches(PyExc_OverflowError))
767 goto onposoverflow;
768 else
769 return -1;
771 if (i < 0)
772 goto onnegoverflow;
773 if (i > INT_MAX)
774 goto onposoverflow;
775 return (int)i;
777 else {
778 PyErr_SetString(PyExc_TypeError,
779 "map size must be an integral value");
780 return -1;
783 onnegoverflow:
784 PyErr_SetString(PyExc_OverflowError,
785 "memory mapped size must be positive");
786 return -1;
788 onposoverflow:
789 PyErr_SetString(PyExc_OverflowError,
790 "memory mapped size is too large (limited by C int)");
791 return -1;
794 #ifdef UNIX
795 static PyObject *
796 new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
798 mmap_object *m_obj;
799 PyObject *map_size_obj = NULL;
800 int map_size;
801 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
802 char *keywords[] = {"file", "size", "flags", "prot", NULL};
804 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
805 "iO|ii", keywords,
806 &fd, &map_size_obj, &flags, &prot)
808 return NULL;
809 map_size = _GetMapSize(map_size_obj);
810 if (map_size < 0)
811 return NULL;
813 m_obj = PyObject_New (mmap_object, &mmap_object_type);
814 if (m_obj == NULL) {return NULL;}
815 m_obj->size = (size_t) map_size;
816 m_obj->pos = (size_t) 0;
817 m_obj->fd = fd;
818 m_obj->data = mmap(NULL, map_size,
819 prot, flags,
820 fd, 0);
821 if (m_obj->data == (char *)-1)
823 Py_DECREF(m_obj);
824 PyErr_SetFromErrno(mmap_module_error);
825 return NULL;
827 return (PyObject *)m_obj;
829 #endif /* UNIX */
831 #ifdef MS_WIN32
832 static PyObject *
833 new_mmap_object(PyObject *self, PyObject *args)
835 mmap_object *m_obj;
836 PyObject *map_size_obj = NULL;
837 int map_size;
838 char *tagname = "";
840 DWORD dwErr = 0;
841 int fileno;
842 HANDLE fh = 0;
844 if (!PyArg_ParseTuple(args,
845 "iO|z",
846 &fileno,
847 &map_size_obj,
848 &tagname)
850 return NULL;
852 map_size = _GetMapSize(map_size_obj);
853 if (map_size < 0)
854 return NULL;
856 /* if an actual filename has been specified */
857 if (fileno != 0) {
858 fh = (HANDLE)_get_osfhandle(fileno);
859 if (fh==(HANDLE)-1) {
860 PyErr_SetFromErrno(mmap_module_error);
861 return NULL;
863 /* Win9x appears to need us seeked to zero */
864 fseek(&_iob[fileno], 0, SEEK_SET);
867 m_obj = PyObject_New (mmap_object, &mmap_object_type);
868 if (m_obj==NULL)
869 return NULL;
870 /* Set every field to an invalid marker, so we can safely
871 destruct the object in the face of failure */
872 m_obj->data = NULL;
873 m_obj->file_handle = INVALID_HANDLE_VALUE;
874 m_obj->map_handle = INVALID_HANDLE_VALUE;
875 m_obj->tagname = NULL;
877 if (fh) {
878 /* It is necessary to duplicate the handle, so the
879 Python code can close it on us */
880 if (!DuplicateHandle(
881 GetCurrentProcess(), /* source process handle */
882 fh, /* handle to be duplicated */
883 GetCurrentProcess(), /* target proc handle */
884 (LPHANDLE)&m_obj->file_handle, /* result */
885 0, /* access - ignored due to options value */
886 FALSE, /* inherited by child processes? */
887 DUPLICATE_SAME_ACCESS)) { /* options */
888 dwErr = GetLastError();
889 Py_DECREF(m_obj);
890 PyErr_SetFromWindowsErr(dwErr);
891 return NULL;
893 if (!map_size) {
894 m_obj->size = GetFileSize (fh, NULL);
895 } else {
896 m_obj->size = map_size;
899 else {
900 m_obj->size = map_size;
903 /* set the initial position */
904 m_obj->pos = (size_t) 0;
906 /* set the tag name */
907 if (tagname != NULL && *tagname != '\0') {
908 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
909 if (m_obj->tagname == NULL) {
910 PyErr_NoMemory();
911 Py_DECREF(m_obj);
912 return NULL;
914 strcpy(m_obj->tagname, tagname);
916 else
917 m_obj->tagname = NULL;
919 m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
920 NULL,
921 PAGE_READWRITE,
923 m_obj->size,
924 m_obj->tagname);
925 if (m_obj->map_handle != NULL) {
926 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
927 FILE_MAP_WRITE,
931 if (m_obj->data != NULL) {
932 return ((PyObject *) m_obj);
933 } else {
934 dwErr = GetLastError();
936 } else {
937 dwErr = GetLastError();
939 Py_DECREF(m_obj);
940 PyErr_SetFromWindowsErr(dwErr);
941 return (NULL);
943 #endif /* MS_WIN32 */
945 /* List of functions exported by this module */
946 static struct PyMethodDef mmap_functions[] = {
947 {"mmap", (PyCFunction) new_mmap_object,
948 METH_VARARGS|METH_KEYWORDS},
949 {NULL, NULL} /* Sentinel */
952 DL_EXPORT(void)
953 initmmap(void)
955 PyObject *dict, *module;
957 /* Patch the object type */
958 mmap_object_type.ob_type = &PyType_Type;
960 module = Py_InitModule ("mmap", mmap_functions);
961 dict = PyModule_GetDict (module);
962 mmap_module_error = PyExc_EnvironmentError;
963 Py_INCREF(mmap_module_error);
964 PyDict_SetItemString (dict, "error", mmap_module_error);
965 #ifdef PROT_EXEC
966 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
967 #endif
968 #ifdef PROT_READ
969 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
970 #endif
971 #ifdef PROT_WRITE
972 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
973 #endif
975 #ifdef MAP_SHARED
976 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
977 #endif
978 #ifdef MAP_PRIVATE
979 PyDict_SetItemString (dict, "MAP_PRIVATE",
980 PyInt_FromLong(MAP_PRIVATE) );
981 #endif
982 #ifdef MAP_DENYWRITE
983 PyDict_SetItemString (dict, "MAP_DENYWRITE",
984 PyInt_FromLong(MAP_DENYWRITE) );
985 #endif
986 #ifdef MAP_EXECUTABLE
987 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
988 PyInt_FromLong(MAP_EXECUTABLE) );
989 #endif
990 #ifdef MAP_ANON
991 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
992 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
993 PyInt_FromLong(MAP_ANON) );
994 #endif
996 PyDict_SetItemString (dict, "PAGESIZE",
997 PyInt_FromLong( (long)my_getpagesize() ) );