Bump version to 0.9.1.
[python/dscho.git] / Modules / mmapmodule.c
blob467f110ead6459f63035b10643fad2759d63ae84
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 #endif
31 #ifdef UNIX
32 #include <unistd.h>
33 #include <sys/mman.h>
34 #include <sys/stat.h>
35 #endif
37 #include <string.h>
38 #include <sys/types.h>
40 static PyObject *mmap_module_error;
42 typedef struct {
43 PyObject_HEAD
44 char * data;
45 size_t size;
46 size_t pos;
48 #ifdef MS_WIN32
49 HANDLE map_handle;
50 HANDLE file_handle;
51 char * tagname;
52 #endif
54 #ifdef UNIX
55 int fd;
56 #endif
57 } mmap_object;
59 static void
60 mmap_object_dealloc(mmap_object *m_obj)
62 #ifdef MS_WIN32
63 if (m_obj->data != NULL)
64 UnmapViewOfFile (m_obj->data);
65 if (m_obj->map_handle != INVALID_HANDLE_VALUE)
66 CloseHandle (m_obj->map_handle);
67 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
68 CloseHandle (m_obj->file_handle);
69 if (m_obj->tagname)
70 PyMem_Free(m_obj->tagname);
71 #endif /* MS_WIN32 */
73 #ifdef UNIX
74 if (m_obj->data!=NULL) {
75 msync(m_obj->data, m_obj->size, MS_SYNC);
76 munmap(m_obj->data, m_obj->size);
78 #endif /* UNIX */
80 PyObject_Del(m_obj);
83 static PyObject *
84 mmap_close_method(mmap_object *self, PyObject *args)
86 if (!PyArg_ParseTuple(args, ":close"))
87 return NULL;
88 #ifdef MS_WIN32
89 /* For each resource we maintain, we need to check
90 the value is valid, and if so, free the resource
91 and set the member value to an invalid value so
92 the dealloc does not attempt to resource clearing
93 again.
94 TODO - should we check for errors in the close operations???
96 if (self->data != NULL) {
97 UnmapViewOfFile (self->data);
98 self->data = NULL;
100 if (self->map_handle != INVALID_HANDLE_VALUE) {
101 CloseHandle (self->map_handle);
102 self->map_handle = INVALID_HANDLE_VALUE;
104 if (self->file_handle != INVALID_HANDLE_VALUE) {
105 CloseHandle (self->file_handle);
106 self->file_handle = INVALID_HANDLE_VALUE;
108 #endif /* MS_WIN32 */
110 #ifdef UNIX
111 munmap(self->data, self->size);
112 self->data = NULL;
113 #endif
115 Py_INCREF (Py_None);
116 return (Py_None);
119 #ifdef MS_WIN32
120 #define CHECK_VALID(err) \
121 do { \
122 if (!self->map_handle) { \
123 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
124 return err; \
126 } while (0)
127 #endif /* MS_WIN32 */
129 #ifdef UNIX
130 #define CHECK_VALID(err) \
131 do { \
132 if (self->data == NULL) { \
133 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
134 return err; \
136 } while (0)
137 #endif /* UNIX */
139 static PyObject *
140 mmap_read_byte_method(mmap_object *self,
141 PyObject *args)
143 char value;
144 char *where;
145 CHECK_VALID(NULL);
146 if (!PyArg_ParseTuple(args, ":read_byte"))
147 return NULL;
148 if (self->pos < self->size) {
149 where = self->data + self->pos;
150 value = (char) *(where);
151 self->pos += 1;
152 return Py_BuildValue("c", (char) *(where));
153 } else {
154 PyErr_SetString (PyExc_ValueError, "read byte out of range");
155 return NULL;
159 static PyObject *
160 mmap_read_line_method(mmap_object *self,
161 PyObject *args)
163 char *start = self->data+self->pos;
164 char *eof = self->data+self->size;
165 char *eol;
166 PyObject *result;
168 CHECK_VALID(NULL);
169 if (!PyArg_ParseTuple(args, ":readline"))
170 return NULL;
172 eol = memchr(start, '\n', self->size - self->pos);
173 if (!eol)
174 eol = eof;
175 else
176 ++eol; /* we're interested in the position after the
177 newline. */
178 result = PyString_FromStringAndSize(start, (eol - start));
179 self->pos += (eol - start);
180 return (result);
183 static PyObject *
184 mmap_read_method(mmap_object *self,
185 PyObject *args)
187 long num_bytes;
188 PyObject *result;
190 CHECK_VALID(NULL);
191 if (!PyArg_ParseTuple(args, "l:read", &num_bytes))
192 return(NULL);
194 /* silently 'adjust' out-of-range requests */
195 if ((self->pos + num_bytes) > self->size) {
196 num_bytes -= (self->pos+num_bytes) - self->size;
198 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
199 self->pos += num_bytes;
200 return (result);
203 static PyObject *
204 mmap_find_method(mmap_object *self,
205 PyObject *args)
207 int start = self->pos;
208 char *needle;
209 int len;
211 CHECK_VALID(NULL);
212 if (!PyArg_ParseTuple (args, "s#|i:find", &needle, &len, &start)) {
213 return NULL;
214 } else {
215 char *p = self->data+self->pos;
216 char *e = self->data+self->size;
217 while (p < e) {
218 char *s = p;
219 char *n = needle;
220 while ((s<e) && (*n) && !(*s-*n)) {
221 s++, n++;
223 if (!*n) {
224 return Py_BuildValue (
225 "i",
226 (int) (p - (self->data + start)));
228 p++;
230 return Py_BuildValue ("l", (long) -1);
234 static PyObject *
235 mmap_write_method(mmap_object *self,
236 PyObject *args)
238 long length;
239 char *data;
241 CHECK_VALID(NULL);
242 if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
243 return(NULL);
245 if ((self->pos + length) > self->size) {
246 PyErr_SetString (PyExc_ValueError, "data out of range");
247 return NULL;
249 memcpy (self->data+self->pos, data, length);
250 self->pos = self->pos+length;
251 Py_INCREF (Py_None);
252 return (Py_None);
255 static PyObject *
256 mmap_write_byte_method(mmap_object *self,
257 PyObject *args)
259 char value;
261 CHECK_VALID(NULL);
262 if (!PyArg_ParseTuple (args, "c:write_byte", &value))
263 return(NULL);
265 *(self->data+self->pos) = value;
266 self->pos += 1;
267 Py_INCREF (Py_None);
268 return (Py_None);
271 static PyObject *
272 mmap_size_method(mmap_object *self,
273 PyObject *args)
275 CHECK_VALID(NULL);
276 if (!PyArg_ParseTuple(args, ":size"))
277 return NULL;
279 #ifdef MS_WIN32
280 if (self->file_handle != INVALID_HANDLE_VALUE) {
281 return (Py_BuildValue (
282 "l", (long)
283 GetFileSize (self->file_handle, NULL)));
284 } else {
285 return (Py_BuildValue ("l", (long) self->size) );
287 #endif /* MS_WIN32 */
289 #ifdef UNIX
291 struct stat buf;
292 if (-1 == fstat(self->fd, &buf)) {
293 PyErr_SetFromErrno(mmap_module_error);
294 return NULL;
296 return (Py_BuildValue ("l", (long) buf.st_size) );
298 #endif /* UNIX */
301 /* This assumes that you want the entire file mapped,
302 / and when recreating the map will make the new file
303 / have the new size
305 / Is this really necessary? This could easily be done
306 / from python by just closing and re-opening with the
307 / new size?
310 static PyObject *
311 mmap_resize_method(mmap_object *self,
312 PyObject *args)
314 unsigned long new_size;
315 CHECK_VALID(NULL);
316 if (!PyArg_ParseTuple (args, "l:resize", &new_size)) {
317 return NULL;
318 #ifdef MS_WIN32
319 } else {
320 DWORD dwErrCode = 0;
321 /* First, unmap the file view */
322 UnmapViewOfFile (self->data);
323 /* Close the mapping object */
324 CloseHandle (self->map_handle);
325 /* Move to the desired EOF position */
326 SetFilePointer (self->file_handle,
327 new_size, NULL, FILE_BEGIN);
328 /* Change the size of the file */
329 SetEndOfFile (self->file_handle);
330 /* Create another mapping object and remap the file view */
331 self->map_handle = CreateFileMapping (
332 self->file_handle,
333 NULL,
334 PAGE_READWRITE,
336 new_size,
337 self->tagname);
338 if (self->map_handle != NULL) {
339 self->data = (char *) MapViewOfFile (self->map_handle,
340 FILE_MAP_WRITE,
344 if (self->data != NULL) {
345 self->size = new_size;
346 Py_INCREF (Py_None);
347 return Py_None;
348 } else {
349 dwErrCode = GetLastError();
351 } else {
352 dwErrCode = GetLastError();
354 PyErr_SetFromWindowsErr(dwErrCode);
355 return (NULL);
356 #endif /* MS_WIN32 */
358 #ifdef UNIX
359 #ifndef HAVE_MREMAP
360 } else {
361 PyErr_SetString(PyExc_SystemError,
362 "mmap: resizing not available--no mremap()");
363 return NULL;
364 #else
365 } else {
366 void *newmap;
368 #ifdef MREMAP_MAYMOVE
369 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
370 #else
371 newmap = mremap(self->data, self->size, new_size, 0);
372 #endif
373 if (newmap == (void *)-1)
375 PyErr_SetFromErrno(mmap_module_error);
376 return NULL;
378 self->data = newmap;
379 self->size = new_size;
380 Py_INCREF(Py_None);
381 return Py_None;
382 #endif /* HAVE_MREMAP */
383 #endif /* UNIX */
387 static PyObject *
388 mmap_tell_method(mmap_object *self, PyObject *args)
390 CHECK_VALID(NULL);
391 if (!PyArg_ParseTuple(args, ":tell"))
392 return NULL;
393 return (Py_BuildValue ("l", (long) self->pos) );
396 static PyObject *
397 mmap_flush_method(mmap_object *self, PyObject *args)
399 size_t offset = 0;
400 size_t size = self->size;
401 CHECK_VALID(NULL);
402 if (!PyArg_ParseTuple (args, "|ll:flush", &offset, &size)) {
403 return NULL;
404 } else if ((offset + size) > self->size) {
405 PyErr_SetString (PyExc_ValueError,
406 "flush values out of range");
407 return NULL;
408 } else {
409 #ifdef MS_WIN32
410 return (Py_BuildValue("l", (long)
411 FlushViewOfFile(self->data+offset, size)));
412 #endif /* MS_WIN32 */
413 #ifdef UNIX
414 /* XXX semantics of return value? */
415 /* XXX flags for msync? */
416 if (-1 == msync(self->data + offset, size,
417 MS_SYNC))
419 PyErr_SetFromErrno(mmap_module_error);
420 return NULL;
422 return Py_BuildValue ("l", (long) 0);
423 #endif /* UNIX */
427 static PyObject *
428 mmap_seek_method(mmap_object *self, PyObject *args)
430 int dist;
431 int how=0;
432 CHECK_VALID(NULL);
433 if (!PyArg_ParseTuple (args, "i|i:seek", &dist, &how)) {
434 return(NULL);
435 } else {
436 size_t where;
437 switch (how) {
438 case 0: /* relative to start */
439 if (dist < 0)
440 goto onoutofrange;
441 where = dist;
442 break;
443 case 1: /* relative to current position */
444 if ((int)self->pos + dist < 0)
445 goto onoutofrange;
446 where = self->pos + dist;
447 break;
448 case 2: /* relative to end */
449 if ((int)self->size + dist < 0)
450 goto onoutofrange;
451 where = self->size + dist;
452 break;
453 default:
454 PyErr_SetString (PyExc_ValueError,
455 "unknown seek type");
456 return NULL;
458 if (where > self->size)
459 goto onoutofrange;
460 self->pos = where;
461 Py_INCREF (Py_None);
462 return (Py_None);
465 onoutofrange:
466 PyErr_SetString (PyExc_ValueError, "seek out of range");
467 return NULL;
470 static PyObject *
471 mmap_move_method(mmap_object *self, PyObject *args)
473 unsigned long dest, src, count;
474 CHECK_VALID(NULL);
475 if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count)) {
476 return NULL;
477 } else {
478 /* bounds check the values */
479 if (/* end of source after end of data?? */
480 ((src+count) > self->size)
481 /* dest will fit? */
482 || (dest+count > self->size)) {
483 PyErr_SetString (PyExc_ValueError,
484 "source or destination out of range");
485 return NULL;
486 } else {
487 memmove (self->data+dest, self->data+src, count);
488 Py_INCREF (Py_None);
489 return Py_None;
494 static struct PyMethodDef mmap_object_methods[] = {
495 {"close", (PyCFunction) mmap_close_method, 1},
496 {"find", (PyCFunction) mmap_find_method, 1},
497 {"flush", (PyCFunction) mmap_flush_method, 1},
498 {"move", (PyCFunction) mmap_move_method, 1},
499 {"read", (PyCFunction) mmap_read_method, 1},
500 {"read_byte", (PyCFunction) mmap_read_byte_method, 1},
501 {"readline", (PyCFunction) mmap_read_line_method, 1},
502 {"resize", (PyCFunction) mmap_resize_method, 1},
503 {"seek", (PyCFunction) mmap_seek_method, 1},
504 {"size", (PyCFunction) mmap_size_method, 1},
505 {"tell", (PyCFunction) mmap_tell_method, 1},
506 {"write", (PyCFunction) mmap_write_method, 1},
507 {"write_byte", (PyCFunction) mmap_write_byte_method, 1},
508 {NULL, NULL} /* sentinel */
511 /* Functions for treating an mmap'ed file as a buffer */
513 static int
514 mmap_buffer_getreadbuf(mmap_object *self, int index, const void **ptr)
516 CHECK_VALID(-1);
517 if ( index != 0 ) {
518 PyErr_SetString(PyExc_SystemError,
519 "Accessing non-existent mmap segment");
520 return -1;
522 *ptr = self->data;
523 return self->size;
526 static int
527 mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
529 CHECK_VALID(-1);
530 if ( index != 0 ) {
531 PyErr_SetString(PyExc_SystemError,
532 "Accessing non-existent mmap segment");
533 return -1;
535 *ptr = self->data;
536 return self->size;
539 static int
540 mmap_buffer_getsegcount(mmap_object *self, int *lenp)
542 CHECK_VALID(-1);
543 if (lenp)
544 *lenp = self->size;
545 return 1;
548 static int
549 mmap_buffer_getcharbuffer(mmap_object *self, int index, const void **ptr)
551 if ( index != 0 ) {
552 PyErr_SetString(PyExc_SystemError,
553 "accessing non-existent buffer segment");
554 return -1;
556 *ptr = (const char *)self->data;
557 return self->size;
560 static PyObject *
561 mmap_object_getattr(mmap_object *self, char *name)
563 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
566 static int
567 mmap_length(mmap_object *self)
569 CHECK_VALID(-1);
570 return self->size;
573 static PyObject *
574 mmap_item(mmap_object *self, int i)
576 CHECK_VALID(NULL);
577 if (i < 0 || (size_t)i >= self->size) {
578 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
579 return NULL;
581 return PyString_FromStringAndSize(self->data + i, 1);
584 static PyObject *
585 mmap_slice(mmap_object *self, int ilow, int ihigh)
587 CHECK_VALID(NULL);
588 if (ilow < 0)
589 ilow = 0;
590 else if ((size_t)ilow > self->size)
591 ilow = self->size;
592 if (ihigh < 0)
593 ihigh = 0;
594 if (ihigh < ilow)
595 ihigh = ilow;
596 else if ((size_t)ihigh > self->size)
597 ihigh = self->size;
599 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
602 static PyObject *
603 mmap_concat(mmap_object *self, PyObject *bb)
605 CHECK_VALID(NULL);
606 PyErr_SetString(PyExc_SystemError,
607 "mmaps don't support concatenation");
608 return NULL;
611 static PyObject *
612 mmap_repeat(mmap_object *self, int n)
614 CHECK_VALID(NULL);
615 PyErr_SetString(PyExc_SystemError,
616 "mmaps don't support repeat operation");
617 return NULL;
620 static int
621 mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
623 const char *buf;
625 CHECK_VALID(-1);
626 if (ilow < 0)
627 ilow = 0;
628 else if ((size_t)ilow > self->size)
629 ilow = self->size;
630 if (ihigh < 0)
631 ihigh = 0;
632 if (ihigh < ilow)
633 ihigh = ilow;
634 else if ((size_t)ihigh > self->size)
635 ihigh = self->size;
637 if (! (PyString_Check(v)) ) {
638 PyErr_SetString(PyExc_IndexError,
639 "mmap slice assignment must be a string");
640 return -1;
642 if ( PyString_Size(v) != (ihigh - ilow) ) {
643 PyErr_SetString(PyExc_IndexError,
644 "mmap slice assignment is wrong size");
645 return -1;
647 buf = PyString_AsString(v);
648 memcpy(self->data + ilow, buf, ihigh-ilow);
649 return 0;
652 static int
653 mmap_ass_item(mmap_object *self, int i, PyObject *v)
655 const char *buf;
657 CHECK_VALID(-1);
658 if (i < 0 || (size_t)i >= self->size) {
659 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
660 return -1;
662 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
663 PyErr_SetString(PyExc_IndexError,
664 "mmap assignment must be single-character string");
665 return -1;
667 buf = PyString_AsString(v);
668 self->data[i] = buf[0];
669 return 0;
672 static PySequenceMethods mmap_as_sequence = {
673 (inquiry)mmap_length, /*sq_length*/
674 (binaryfunc)mmap_concat, /*sq_concat*/
675 (intargfunc)mmap_repeat, /*sq_repeat*/
676 (intargfunc)mmap_item, /*sq_item*/
677 (intintargfunc)mmap_slice, /*sq_slice*/
678 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
679 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
682 static PyBufferProcs mmap_as_buffer = {
683 (getreadbufferproc)mmap_buffer_getreadbuf,
684 (getwritebufferproc)mmap_buffer_getwritebuf,
685 (getsegcountproc)mmap_buffer_getsegcount,
686 (getcharbufferproc)mmap_buffer_getcharbuffer,
689 static PyTypeObject mmap_object_type = {
690 PyObject_HEAD_INIT(0) /* patched in module init */
691 0, /* ob_size */
692 "mmap", /* tp_name */
693 sizeof(mmap_object), /* tp_size */
694 0, /* tp_itemsize */
695 /* methods */
696 (destructor) mmap_object_dealloc, /* tp_dealloc */
697 0, /* tp_print */
698 (getattrfunc) mmap_object_getattr, /* tp_getattr */
699 0, /* tp_setattr */
700 0, /* tp_compare */
701 0, /* tp_repr */
702 0, /* tp_as_number */
703 &mmap_as_sequence, /*tp_as_sequence*/
704 0, /*tp_as_mapping*/
705 0, /*tp_hash*/
706 0, /*tp_call*/
707 0, /*tp_str*/
708 0, /*tp_getattro*/
709 0, /*tp_setattro*/
710 &mmap_as_buffer, /*tp_as_buffer*/
711 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
712 0, /*tp_doc*/
716 /* extract the map size from the given PyObject
718 The map size is restricted to [0, INT_MAX] because this is the current
719 Python limitation on object sizes. Although the mmap object *could* handle
720 a larger map size, there is no point because all the useful operations
721 (len(), slicing(), sequence indexing) are limited by a C int.
723 Returns -1 on error, with an appropriate Python exception raised. On
724 success, the map size is returned. */
725 static int
726 _GetMapSize(PyObject *o)
728 if (PyInt_Check(o)) {
729 long i = PyInt_AsLong(o);
730 if (PyErr_Occurred())
731 return -1;
732 if (i < 0)
733 goto onnegoverflow;
734 if (i > INT_MAX)
735 goto onposoverflow;
736 return (int)i;
738 else if (PyLong_Check(o)) {
739 long i = PyLong_AsLong(o);
740 if (PyErr_Occurred()) {
741 /* yes negative overflow is mistaken for positive overflow
742 but not worth the trouble to check sign of 'i' */
743 if (PyErr_ExceptionMatches(PyExc_OverflowError))
744 goto onposoverflow;
745 else
746 return -1;
748 if (i < 0)
749 goto onnegoverflow;
750 if (i > INT_MAX)
751 goto onposoverflow;
752 return (int)i;
754 else {
755 PyErr_SetString(PyExc_TypeError,
756 "map size must be an integral value");
757 return -1;
760 onnegoverflow:
761 PyErr_SetString(PyExc_OverflowError,
762 "memory mapped size must be positive");
763 return -1;
765 onposoverflow:
766 PyErr_SetString(PyExc_OverflowError,
767 "memory mapped size is too large (limited by C int)");
768 return -1;
771 #ifdef UNIX
772 static PyObject *
773 new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
775 mmap_object *m_obj;
776 PyObject *map_size_obj = NULL;
777 int map_size;
778 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
779 char *keywords[] = {"file", "size", "flags", "prot", NULL};
781 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
782 "iO|ii", keywords,
783 &fd, &map_size_obj, &flags, &prot)
785 return NULL;
786 map_size = _GetMapSize(map_size_obj);
787 if (map_size < 0)
788 return NULL;
790 m_obj = PyObject_New (mmap_object, &mmap_object_type);
791 if (m_obj == NULL) {return NULL;}
792 m_obj->size = (size_t) map_size;
793 m_obj->pos = (size_t) 0;
794 m_obj->fd = fd;
795 m_obj->data = mmap(NULL, map_size,
796 prot, flags,
797 fd, 0);
798 if (m_obj->data == (void *)-1)
800 Py_DECREF(m_obj);
801 PyErr_SetFromErrno(mmap_module_error);
802 return NULL;
804 return (PyObject *)m_obj;
806 #endif /* UNIX */
808 #ifdef MS_WIN32
809 static PyObject *
810 new_mmap_object(PyObject *self, PyObject *args)
812 mmap_object *m_obj;
813 PyObject *map_size_obj = NULL;
814 int map_size;
815 char *tagname = "";
817 DWORD dwErr = 0;
818 int fileno;
819 HANDLE fh = 0;
821 /* Patch the object type */
822 mmap_object_type.ob_type = &PyType_Type;
824 if (!PyArg_ParseTuple(args,
825 "iO|z",
826 &fileno,
827 &map_size_obj,
828 &tagname)
830 return NULL;
832 map_size = _GetMapSize(map_size_obj);
833 if (map_size < 0)
834 return NULL;
836 /* if an actual filename has been specified */
837 if (fileno != 0) {
838 fh = (HANDLE)_get_osfhandle(fileno);
839 if (fh==(HANDLE)-1) {
840 PyErr_SetFromErrno(mmap_module_error);
841 return NULL;
843 /* Win9x appears to need us seeked to zero */
844 fseek(&_iob[fileno], 0, SEEK_SET);
847 m_obj = PyObject_New (mmap_object, &mmap_object_type);
848 if (m_obj==NULL)
849 return NULL;
850 /* Set every field to an invalid marker, so we can safely
851 destruct the object in the face of failure */
852 m_obj->data = NULL;
853 m_obj->file_handle = INVALID_HANDLE_VALUE;
854 m_obj->map_handle = INVALID_HANDLE_VALUE;
855 m_obj->tagname = NULL;
857 if (fh) {
858 /* It is necessary to duplicate the handle, so the
859 Python code can close it on us */
860 if (!DuplicateHandle(
861 GetCurrentProcess(), /* source process handle */
862 fh, /* handle to be duplicated */
863 GetCurrentProcess(), /* target proc handle */
864 (LPHANDLE)&m_obj->file_handle, /* result */
865 0, /* access - ignored due to options value */
866 FALSE, /* inherited by child processes? */
867 DUPLICATE_SAME_ACCESS)) { /* options */
868 dwErr = GetLastError();
869 Py_DECREF(m_obj);
870 PyErr_SetFromWindowsErr(dwErr);
871 return NULL;
873 if (!map_size) {
874 m_obj->size = GetFileSize (fh, NULL);
875 } else {
876 m_obj->size = map_size;
879 else {
880 m_obj->size = map_size;
883 /* set the initial position */
884 m_obj->pos = (size_t) 0;
886 /* set the tag name */
887 if (tagname != NULL) {
888 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
889 if (m_obj->tagname == NULL) {
890 PyErr_NoMemory();
891 Py_DECREF(m_obj);
892 return NULL;
894 strcpy(m_obj->tagname, tagname);
896 else
897 m_obj->tagname = NULL;
899 m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
900 NULL,
901 PAGE_READWRITE,
903 m_obj->size,
904 tagname);
905 if (m_obj->map_handle != NULL) {
906 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
907 FILE_MAP_WRITE,
911 if (m_obj->data != NULL) {
912 return ((PyObject *) m_obj);
913 } else {
914 dwErr = GetLastError();
916 } else {
917 dwErr = GetLastError();
919 Py_DECREF(m_obj);
920 PyErr_SetFromWindowsErr(dwErr);
921 return (NULL);
923 #endif /* MS_WIN32 */
925 /* List of functions exported by this module */
926 static struct PyMethodDef mmap_functions[] = {
927 {"mmap", (PyCFunction) new_mmap_object,
928 METH_VARARGS|METH_KEYWORDS},
929 {NULL, NULL} /* Sentinel */
932 #ifdef MS_WIN32
933 __declspec(dllexport) void
934 #endif /* MS_WIN32 */
935 #ifdef UNIX
936 extern void
937 #endif
939 initmmap(void)
941 PyObject *dict, *module;
942 module = Py_InitModule ("mmap", mmap_functions);
943 dict = PyModule_GetDict (module);
944 mmap_module_error = PyExc_EnvironmentError;
945 Py_INCREF(mmap_module_error);
946 PyDict_SetItemString (dict, "error", mmap_module_error);
947 #ifdef PROT_EXEC
948 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
949 #endif
950 #ifdef PROT_READ
951 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
952 #endif
953 #ifdef PROT_WRITE
954 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
955 #endif
957 #ifdef MAP_SHARED
958 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
959 #endif
960 #ifdef MAP_PRIVATE
961 PyDict_SetItemString (dict, "MAP_PRIVATE",
962 PyInt_FromLong(MAP_PRIVATE) );
963 #endif
964 #ifdef MAP_DENYWRITE
965 PyDict_SetItemString (dict, "MAP_DENYWRITE",
966 PyInt_FromLong(MAP_DENYWRITE) );
967 #endif
968 #ifdef MAP_EXECUTABLE
969 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
970 PyInt_FromLong(MAP_EXECUTABLE) );
971 #endif
972 #ifdef MAP_ANON
973 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
974 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
975 PyInt_FromLong(MAP_ANON) );
976 #endif
978 #ifdef UNIX
979 PyDict_SetItemString (dict, "PAGESIZE",
980 PyInt_FromLong( (long)getpagesize() ) );
981 #endif
982 #ifdef MS_WIN32
984 SYSTEM_INFO si;
985 GetSystemInfo(&si);
986 PyDict_SetItemString (dict, "PAGESIZE",
987 PyInt_FromLong( si.dwPageSize ) );
989 #endif /* MS_WIN32 */