Merged release21-maint changes.
[python/dscho.git] / Modules / mmapmodule.c
blobd5bc89f309d55842a73714b6c4d729dafdd3859d
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 CHECK_VALID(NULL);
167 if (!PyArg_ParseTuple(args, ":read_byte"))
168 return NULL;
169 if (self->pos < self->size) {
170 char value = self->data[self->pos];
171 self->pos += 1;
172 return Py_BuildValue("c", value);
173 } else {
174 PyErr_SetString (PyExc_ValueError, "read byte out of range");
175 return NULL;
179 static PyObject *
180 mmap_read_line_method(mmap_object *self,
181 PyObject *args)
183 char *start = self->data+self->pos;
184 char *eof = self->data+self->size;
185 char *eol;
186 PyObject *result;
188 CHECK_VALID(NULL);
189 if (!PyArg_ParseTuple(args, ":readline"))
190 return NULL;
192 eol = memchr(start, '\n', self->size - self->pos);
193 if (!eol)
194 eol = eof;
195 else
196 ++eol; /* we're interested in the position after the
197 newline. */
198 result = PyString_FromStringAndSize(start, (eol - start));
199 self->pos += (eol - start);
200 return (result);
203 static PyObject *
204 mmap_read_method(mmap_object *self,
205 PyObject *args)
207 long num_bytes;
208 PyObject *result;
210 CHECK_VALID(NULL);
211 if (!PyArg_ParseTuple(args, "l:read", &num_bytes))
212 return(NULL);
214 /* silently 'adjust' out-of-range requests */
215 if ((self->pos + num_bytes) > self->size) {
216 num_bytes -= (self->pos+num_bytes) - self->size;
218 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
219 self->pos += num_bytes;
220 return (result);
223 static PyObject *
224 mmap_find_method(mmap_object *self,
225 PyObject *args)
227 long start = self->pos;
228 char *needle;
229 int len;
231 CHECK_VALID(NULL);
232 if (!PyArg_ParseTuple (args, "s#|l:find", &needle, &len, &start)) {
233 return NULL;
234 } else {
235 char *p;
236 char *e = self->data + self->size;
238 if (start < 0)
239 start += self->size;
240 if (start < 0)
241 start = 0;
242 else if ((size_t)start > self->size)
243 start = self->size;
244 p = self->data + start;
246 while (p < e) {
247 char *s = p;
248 char *n = needle;
249 while ((s<e) && (*n) && !(*s-*n)) {
250 s++, n++;
252 if (!*n) {
253 return Py_BuildValue (
254 "l",
255 (long) (p - self->data));
257 p++;
259 return Py_BuildValue ("l", (long) -1);
263 static PyObject *
264 mmap_write_method(mmap_object *self,
265 PyObject *args)
267 long length;
268 char *data;
270 CHECK_VALID(NULL);
271 if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
272 return(NULL);
274 if ((self->pos + length) > self->size) {
275 PyErr_SetString (PyExc_ValueError, "data out of range");
276 return NULL;
278 memcpy (self->data+self->pos, data, length);
279 self->pos = self->pos+length;
280 Py_INCREF (Py_None);
281 return (Py_None);
284 static PyObject *
285 mmap_write_byte_method(mmap_object *self,
286 PyObject *args)
288 char value;
290 CHECK_VALID(NULL);
291 if (!PyArg_ParseTuple (args, "c:write_byte", &value))
292 return(NULL);
294 *(self->data+self->pos) = value;
295 self->pos += 1;
296 Py_INCREF (Py_None);
297 return (Py_None);
300 static PyObject *
301 mmap_size_method(mmap_object *self,
302 PyObject *args)
304 CHECK_VALID(NULL);
305 if (!PyArg_ParseTuple(args, ":size"))
306 return NULL;
308 #ifdef MS_WIN32
309 if (self->file_handle != INVALID_HANDLE_VALUE) {
310 return (Py_BuildValue (
311 "l", (long)
312 GetFileSize (self->file_handle, NULL)));
313 } else {
314 return (Py_BuildValue ("l", (long) self->size) );
316 #endif /* MS_WIN32 */
318 #ifdef UNIX
320 struct stat buf;
321 if (-1 == fstat(self->fd, &buf)) {
322 PyErr_SetFromErrno(mmap_module_error);
323 return NULL;
325 return (Py_BuildValue ("l", (long) buf.st_size) );
327 #endif /* UNIX */
330 /* This assumes that you want the entire file mapped,
331 / and when recreating the map will make the new file
332 / have the new size
334 / Is this really necessary? This could easily be done
335 / from python by just closing and re-opening with the
336 / new size?
339 static PyObject *
340 mmap_resize_method(mmap_object *self,
341 PyObject *args)
343 unsigned long new_size;
344 CHECK_VALID(NULL);
345 if (!PyArg_ParseTuple (args, "l:resize", &new_size)) {
346 return NULL;
347 #ifdef MS_WIN32
348 } else {
349 DWORD dwErrCode = 0;
350 /* First, unmap the file view */
351 UnmapViewOfFile (self->data);
352 /* Close the mapping object */
353 CloseHandle (self->map_handle);
354 /* Move to the desired EOF position */
355 SetFilePointer (self->file_handle,
356 new_size, NULL, FILE_BEGIN);
357 /* Change the size of the file */
358 SetEndOfFile (self->file_handle);
359 /* Create another mapping object and remap the file view */
360 self->map_handle = CreateFileMapping (
361 self->file_handle,
362 NULL,
363 PAGE_READWRITE,
365 new_size,
366 self->tagname);
367 if (self->map_handle != NULL) {
368 self->data = (char *) MapViewOfFile (self->map_handle,
369 FILE_MAP_WRITE,
373 if (self->data != NULL) {
374 self->size = new_size;
375 Py_INCREF (Py_None);
376 return Py_None;
377 } else {
378 dwErrCode = GetLastError();
380 } else {
381 dwErrCode = GetLastError();
383 PyErr_SetFromWindowsErr(dwErrCode);
384 return (NULL);
385 #endif /* MS_WIN32 */
387 #ifdef UNIX
388 #ifndef HAVE_MREMAP
389 } else {
390 PyErr_SetString(PyExc_SystemError,
391 "mmap: resizing not available--no mremap()");
392 return NULL;
393 #else
394 } else {
395 void *newmap;
397 #ifdef MREMAP_MAYMOVE
398 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
399 #else
400 newmap = mremap(self->data, self->size, new_size, 0);
401 #endif
402 if (newmap == (void *)-1)
404 PyErr_SetFromErrno(mmap_module_error);
405 return NULL;
407 self->data = newmap;
408 self->size = new_size;
409 Py_INCREF(Py_None);
410 return Py_None;
411 #endif /* HAVE_MREMAP */
412 #endif /* UNIX */
416 static PyObject *
417 mmap_tell_method(mmap_object *self, PyObject *args)
419 CHECK_VALID(NULL);
420 if (!PyArg_ParseTuple(args, ":tell"))
421 return NULL;
422 return (Py_BuildValue ("l", (long) self->pos) );
425 static PyObject *
426 mmap_flush_method(mmap_object *self, PyObject *args)
428 size_t offset = 0;
429 size_t size = self->size;
430 CHECK_VALID(NULL);
431 if (!PyArg_ParseTuple (args, "|ll:flush", &offset, &size)) {
432 return NULL;
433 } else if ((offset + size) > self->size) {
434 PyErr_SetString (PyExc_ValueError,
435 "flush values out of range");
436 return NULL;
437 } else {
438 #ifdef MS_WIN32
439 return (Py_BuildValue("l", (long)
440 FlushViewOfFile(self->data+offset, size)));
441 #endif /* MS_WIN32 */
442 #ifdef UNIX
443 /* XXX semantics of return value? */
444 /* XXX flags for msync? */
445 if (-1 == msync(self->data + offset, size,
446 MS_SYNC))
448 PyErr_SetFromErrno(mmap_module_error);
449 return NULL;
451 return Py_BuildValue ("l", (long) 0);
452 #endif /* UNIX */
456 static PyObject *
457 mmap_seek_method(mmap_object *self, PyObject *args)
459 int dist;
460 int how=0;
461 CHECK_VALID(NULL);
462 if (!PyArg_ParseTuple (args, "i|i:seek", &dist, &how)) {
463 return(NULL);
464 } else {
465 size_t where;
466 switch (how) {
467 case 0: /* relative to start */
468 if (dist < 0)
469 goto onoutofrange;
470 where = dist;
471 break;
472 case 1: /* relative to current position */
473 if ((int)self->pos + dist < 0)
474 goto onoutofrange;
475 where = self->pos + dist;
476 break;
477 case 2: /* relative to end */
478 if ((int)self->size + dist < 0)
479 goto onoutofrange;
480 where = self->size + dist;
481 break;
482 default:
483 PyErr_SetString (PyExc_ValueError,
484 "unknown seek type");
485 return NULL;
487 if (where > self->size)
488 goto onoutofrange;
489 self->pos = where;
490 Py_INCREF (Py_None);
491 return (Py_None);
494 onoutofrange:
495 PyErr_SetString (PyExc_ValueError, "seek out of range");
496 return NULL;
499 static PyObject *
500 mmap_move_method(mmap_object *self, PyObject *args)
502 unsigned long dest, src, count;
503 CHECK_VALID(NULL);
504 if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count)) {
505 return NULL;
506 } else {
507 /* bounds check the values */
508 if (/* end of source after end of data?? */
509 ((src+count) > self->size)
510 /* dest will fit? */
511 || (dest+count > self->size)) {
512 PyErr_SetString (PyExc_ValueError,
513 "source or destination out of range");
514 return NULL;
515 } else {
516 memmove (self->data+dest, self->data+src, count);
517 Py_INCREF (Py_None);
518 return Py_None;
523 static struct PyMethodDef mmap_object_methods[] = {
524 {"close", (PyCFunction) mmap_close_method, 1},
525 {"find", (PyCFunction) mmap_find_method, 1},
526 {"flush", (PyCFunction) mmap_flush_method, 1},
527 {"move", (PyCFunction) mmap_move_method, 1},
528 {"read", (PyCFunction) mmap_read_method, 1},
529 {"read_byte", (PyCFunction) mmap_read_byte_method, 1},
530 {"readline", (PyCFunction) mmap_read_line_method, 1},
531 {"resize", (PyCFunction) mmap_resize_method, 1},
532 {"seek", (PyCFunction) mmap_seek_method, 1},
533 {"size", (PyCFunction) mmap_size_method, 1},
534 {"tell", (PyCFunction) mmap_tell_method, 1},
535 {"write", (PyCFunction) mmap_write_method, 1},
536 {"write_byte", (PyCFunction) mmap_write_byte_method, 1},
537 {NULL, NULL} /* sentinel */
540 /* Functions for treating an mmap'ed file as a buffer */
542 static int
543 mmap_buffer_getreadbuf(mmap_object *self, int index, const void **ptr)
545 CHECK_VALID(-1);
546 if ( index != 0 ) {
547 PyErr_SetString(PyExc_SystemError,
548 "Accessing non-existent mmap segment");
549 return -1;
551 *ptr = self->data;
552 return self->size;
555 static int
556 mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
558 CHECK_VALID(-1);
559 if ( index != 0 ) {
560 PyErr_SetString(PyExc_SystemError,
561 "Accessing non-existent mmap segment");
562 return -1;
564 *ptr = self->data;
565 return self->size;
568 static int
569 mmap_buffer_getsegcount(mmap_object *self, int *lenp)
571 CHECK_VALID(-1);
572 if (lenp)
573 *lenp = self->size;
574 return 1;
577 static int
578 mmap_buffer_getcharbuffer(mmap_object *self, int index, const void **ptr)
580 if ( index != 0 ) {
581 PyErr_SetString(PyExc_SystemError,
582 "accessing non-existent buffer segment");
583 return -1;
585 *ptr = (const char *)self->data;
586 return self->size;
589 static PyObject *
590 mmap_object_getattr(mmap_object *self, char *name)
592 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
595 static int
596 mmap_length(mmap_object *self)
598 CHECK_VALID(-1);
599 return self->size;
602 static PyObject *
603 mmap_item(mmap_object *self, int i)
605 CHECK_VALID(NULL);
606 if (i < 0 || (size_t)i >= self->size) {
607 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
608 return NULL;
610 return PyString_FromStringAndSize(self->data + i, 1);
613 static PyObject *
614 mmap_slice(mmap_object *self, int ilow, int ihigh)
616 CHECK_VALID(NULL);
617 if (ilow < 0)
618 ilow = 0;
619 else if ((size_t)ilow > self->size)
620 ilow = self->size;
621 if (ihigh < 0)
622 ihigh = 0;
623 if (ihigh < ilow)
624 ihigh = ilow;
625 else if ((size_t)ihigh > self->size)
626 ihigh = self->size;
628 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
631 static PyObject *
632 mmap_concat(mmap_object *self, PyObject *bb)
634 CHECK_VALID(NULL);
635 PyErr_SetString(PyExc_SystemError,
636 "mmaps don't support concatenation");
637 return NULL;
640 static PyObject *
641 mmap_repeat(mmap_object *self, int n)
643 CHECK_VALID(NULL);
644 PyErr_SetString(PyExc_SystemError,
645 "mmaps don't support repeat operation");
646 return NULL;
649 static int
650 mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
652 const char *buf;
654 CHECK_VALID(-1);
655 if (ilow < 0)
656 ilow = 0;
657 else if ((size_t)ilow > self->size)
658 ilow = self->size;
659 if (ihigh < 0)
660 ihigh = 0;
661 if (ihigh < ilow)
662 ihigh = ilow;
663 else if ((size_t)ihigh > self->size)
664 ihigh = self->size;
666 if (v == NULL) {
667 PyErr_SetString(PyExc_TypeError,
668 "mmap object doesn't support slice deletion");
669 return -1;
671 if (! (PyString_Check(v)) ) {
672 PyErr_SetString(PyExc_IndexError,
673 "mmap slice assignment must be a string");
674 return -1;
676 if ( PyString_Size(v) != (ihigh - ilow) ) {
677 PyErr_SetString(PyExc_IndexError,
678 "mmap slice assignment is wrong size");
679 return -1;
681 buf = PyString_AsString(v);
682 memcpy(self->data + ilow, buf, ihigh-ilow);
683 return 0;
686 static int
687 mmap_ass_item(mmap_object *self, int i, PyObject *v)
689 const char *buf;
691 CHECK_VALID(-1);
692 if (i < 0 || (size_t)i >= self->size) {
693 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
694 return -1;
696 if (v == NULL) {
697 PyErr_SetString(PyExc_TypeError,
698 "mmap object doesn't support item deletion");
699 return -1;
701 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
702 PyErr_SetString(PyExc_IndexError,
703 "mmap assignment must be single-character string");
704 return -1;
706 buf = PyString_AsString(v);
707 self->data[i] = buf[0];
708 return 0;
711 static PySequenceMethods mmap_as_sequence = {
712 (inquiry)mmap_length, /*sq_length*/
713 (binaryfunc)mmap_concat, /*sq_concat*/
714 (intargfunc)mmap_repeat, /*sq_repeat*/
715 (intargfunc)mmap_item, /*sq_item*/
716 (intintargfunc)mmap_slice, /*sq_slice*/
717 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
718 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
721 static PyBufferProcs mmap_as_buffer = {
722 (getreadbufferproc)mmap_buffer_getreadbuf,
723 (getwritebufferproc)mmap_buffer_getwritebuf,
724 (getsegcountproc)mmap_buffer_getsegcount,
725 (getcharbufferproc)mmap_buffer_getcharbuffer,
728 static PyTypeObject mmap_object_type = {
729 PyObject_HEAD_INIT(0) /* patched in module init */
730 0, /* ob_size */
731 "mmap", /* tp_name */
732 sizeof(mmap_object), /* tp_size */
733 0, /* tp_itemsize */
734 /* methods */
735 (destructor) mmap_object_dealloc, /* tp_dealloc */
736 0, /* tp_print */
737 (getattrfunc) mmap_object_getattr, /* tp_getattr */
738 0, /* tp_setattr */
739 0, /* tp_compare */
740 0, /* tp_repr */
741 0, /* tp_as_number */
742 &mmap_as_sequence, /*tp_as_sequence*/
743 0, /*tp_as_mapping*/
744 0, /*tp_hash*/
745 0, /*tp_call*/
746 0, /*tp_str*/
747 0, /*tp_getattro*/
748 0, /*tp_setattro*/
749 &mmap_as_buffer, /*tp_as_buffer*/
750 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
751 0, /*tp_doc*/
755 /* extract the map size from the given PyObject
757 The map size is restricted to [0, INT_MAX] because this is the current
758 Python limitation on object sizes. Although the mmap object *could* handle
759 a larger map size, there is no point because all the useful operations
760 (len(), slicing(), sequence indexing) are limited by a C int.
762 Returns -1 on error, with an appropriate Python exception raised. On
763 success, the map size is returned. */
764 static int
765 _GetMapSize(PyObject *o)
767 if (PyInt_Check(o)) {
768 long i = PyInt_AsLong(o);
769 if (PyErr_Occurred())
770 return -1;
771 if (i < 0)
772 goto onnegoverflow;
773 if (i > INT_MAX)
774 goto onposoverflow;
775 return (int)i;
777 else if (PyLong_Check(o)) {
778 long i = PyLong_AsLong(o);
779 if (PyErr_Occurred()) {
780 /* yes negative overflow is mistaken for positive overflow
781 but not worth the trouble to check sign of 'i' */
782 if (PyErr_ExceptionMatches(PyExc_OverflowError))
783 goto onposoverflow;
784 else
785 return -1;
787 if (i < 0)
788 goto onnegoverflow;
789 if (i > INT_MAX)
790 goto onposoverflow;
791 return (int)i;
793 else {
794 PyErr_SetString(PyExc_TypeError,
795 "map size must be an integral value");
796 return -1;
799 onnegoverflow:
800 PyErr_SetString(PyExc_OverflowError,
801 "memory mapped size must be positive");
802 return -1;
804 onposoverflow:
805 PyErr_SetString(PyExc_OverflowError,
806 "memory mapped size is too large (limited by C int)");
807 return -1;
810 #ifdef UNIX
811 static PyObject *
812 new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
814 mmap_object *m_obj;
815 PyObject *map_size_obj = NULL;
816 int map_size;
817 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
818 char *keywords[] = {"file", "size", "flags", "prot", NULL};
820 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
821 "iO|ii", keywords,
822 &fd, &map_size_obj, &flags, &prot)
824 return NULL;
825 map_size = _GetMapSize(map_size_obj);
826 if (map_size < 0)
827 return NULL;
829 m_obj = PyObject_New (mmap_object, &mmap_object_type);
830 if (m_obj == NULL) {return NULL;}
831 m_obj->size = (size_t) map_size;
832 m_obj->pos = (size_t) 0;
833 m_obj->fd = fd;
834 m_obj->data = mmap(NULL, map_size,
835 prot, flags,
836 fd, 0);
837 if (m_obj->data == (char *)-1)
839 Py_DECREF(m_obj);
840 PyErr_SetFromErrno(mmap_module_error);
841 return NULL;
843 return (PyObject *)m_obj;
845 #endif /* UNIX */
847 #ifdef MS_WIN32
848 static PyObject *
849 new_mmap_object(PyObject *self, PyObject *args)
851 mmap_object *m_obj;
852 PyObject *map_size_obj = NULL;
853 int map_size;
854 char *tagname = "";
856 DWORD dwErr = 0;
857 int fileno;
858 HANDLE fh = 0;
860 if (!PyArg_ParseTuple(args,
861 "iO|z",
862 &fileno,
863 &map_size_obj,
864 &tagname)
866 return NULL;
868 map_size = _GetMapSize(map_size_obj);
869 if (map_size < 0)
870 return NULL;
872 /* if an actual filename has been specified */
873 if (fileno != 0) {
874 fh = (HANDLE)_get_osfhandle(fileno);
875 if (fh==(HANDLE)-1) {
876 PyErr_SetFromErrno(mmap_module_error);
877 return NULL;
879 /* Win9x appears to need us seeked to zero */
880 fseek(&_iob[fileno], 0, SEEK_SET);
883 m_obj = PyObject_New (mmap_object, &mmap_object_type);
884 if (m_obj==NULL)
885 return NULL;
886 /* Set every field to an invalid marker, so we can safely
887 destruct the object in the face of failure */
888 m_obj->data = NULL;
889 m_obj->file_handle = INVALID_HANDLE_VALUE;
890 m_obj->map_handle = INVALID_HANDLE_VALUE;
891 m_obj->tagname = NULL;
893 if (fh) {
894 /* It is necessary to duplicate the handle, so the
895 Python code can close it on us */
896 if (!DuplicateHandle(
897 GetCurrentProcess(), /* source process handle */
898 fh, /* handle to be duplicated */
899 GetCurrentProcess(), /* target proc handle */
900 (LPHANDLE)&m_obj->file_handle, /* result */
901 0, /* access - ignored due to options value */
902 FALSE, /* inherited by child processes? */
903 DUPLICATE_SAME_ACCESS)) { /* options */
904 dwErr = GetLastError();
905 Py_DECREF(m_obj);
906 PyErr_SetFromWindowsErr(dwErr);
907 return NULL;
909 if (!map_size) {
910 m_obj->size = GetFileSize (fh, NULL);
911 } else {
912 m_obj->size = map_size;
915 else {
916 m_obj->size = map_size;
919 /* set the initial position */
920 m_obj->pos = (size_t) 0;
922 /* set the tag name */
923 if (tagname != NULL && *tagname != '\0') {
924 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
925 if (m_obj->tagname == NULL) {
926 PyErr_NoMemory();
927 Py_DECREF(m_obj);
928 return NULL;
930 strcpy(m_obj->tagname, tagname);
932 else
933 m_obj->tagname = NULL;
935 m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
936 NULL,
937 PAGE_READWRITE,
939 m_obj->size,
940 m_obj->tagname);
941 if (m_obj->map_handle != NULL) {
942 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
943 FILE_MAP_WRITE,
947 if (m_obj->data != NULL) {
948 return ((PyObject *) m_obj);
949 } else {
950 dwErr = GetLastError();
952 } else {
953 dwErr = GetLastError();
955 Py_DECREF(m_obj);
956 PyErr_SetFromWindowsErr(dwErr);
957 return (NULL);
959 #endif /* MS_WIN32 */
961 /* List of functions exported by this module */
962 static struct PyMethodDef mmap_functions[] = {
963 {"mmap", (PyCFunction) new_mmap_object,
964 METH_VARARGS|METH_KEYWORDS},
965 {NULL, NULL} /* Sentinel */
968 DL_EXPORT(void)
969 initmmap(void)
971 PyObject *dict, *module;
973 /* Patch the object type */
974 mmap_object_type.ob_type = &PyType_Type;
976 module = Py_InitModule ("mmap", mmap_functions);
977 dict = PyModule_GetDict (module);
978 mmap_module_error = PyExc_EnvironmentError;
979 Py_INCREF(mmap_module_error);
980 PyDict_SetItemString (dict, "error", mmap_module_error);
981 #ifdef PROT_EXEC
982 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
983 #endif
984 #ifdef PROT_READ
985 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
986 #endif
987 #ifdef PROT_WRITE
988 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
989 #endif
991 #ifdef MAP_SHARED
992 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
993 #endif
994 #ifdef MAP_PRIVATE
995 PyDict_SetItemString (dict, "MAP_PRIVATE",
996 PyInt_FromLong(MAP_PRIVATE) );
997 #endif
998 #ifdef MAP_DENYWRITE
999 PyDict_SetItemString (dict, "MAP_DENYWRITE",
1000 PyInt_FromLong(MAP_DENYWRITE) );
1001 #endif
1002 #ifdef MAP_EXECUTABLE
1003 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
1004 PyInt_FromLong(MAP_EXECUTABLE) );
1005 #endif
1006 #ifdef MAP_ANON
1007 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
1008 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
1009 PyInt_FromLong(MAP_ANON) );
1010 #endif
1012 PyDict_SetItemString (dict, "PAGESIZE",
1013 PyInt_FromLong( (long)my_getpagesize() ) );