2 / Author: Sam Rushing <rushing@nightmare.com>
3 / Hacked for Unix by AMK
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 / This version of mmapmodule.c has been changed significantly
13 / from the original mmapfile.c on which it was based.
14 / The original version of mmapfile is maintained by Sam at
15 / ftp://squirl.nightmare.com/pub/python/python-ext.
18 #define PY_SSIZE_T_CLEAN
40 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
44 return sysconf(_SC_PAGESIZE
);
47 #define my_getpagesize getpagesize
54 #ifdef HAVE_SYS_TYPES_H
55 #include <sys/types.h>
56 #endif /* HAVE_SYS_TYPES_H */
58 /* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
59 #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
60 # define MAP_ANONYMOUS MAP_ANON
63 static PyObject
*mmap_module_error
;
94 mmap_object_dealloc(mmap_object
*m_obj
)
97 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
);
101 if (m_obj
->file_handle
!= INVALID_HANDLE_VALUE
)
102 CloseHandle (m_obj
->file_handle
);
104 PyMem_Free(m_obj
->tagname
);
105 #endif /* MS_WINDOWS */
109 (void) close(m_obj
->fd
);
110 if (m_obj
->data
!=NULL
) {
111 msync(m_obj
->data
, m_obj
->size
, MS_SYNC
);
112 munmap(m_obj
->data
, m_obj
->size
);
120 mmap_close_method(mmap_object
*self
, PyObject
*unused
)
123 /* 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
128 TODO - should we check for errors in the close operations???
130 if (self
->data
!= NULL
) {
131 UnmapViewOfFile(self
->data
);
134 if (self
->map_handle
!= INVALID_HANDLE_VALUE
) {
135 CloseHandle(self
->map_handle
);
136 self
->map_handle
= INVALID_HANDLE_VALUE
;
138 if (self
->file_handle
!= INVALID_HANDLE_VALUE
) {
139 CloseHandle(self
->file_handle
);
140 self
->file_handle
= INVALID_HANDLE_VALUE
;
142 #endif /* MS_WINDOWS */
145 (void) close(self
->fd
);
147 if (self
->data
!= NULL
) {
148 munmap(self
->data
, self
->size
);
158 #define CHECK_VALID(err) \
160 if (self->map_handle == INVALID_HANDLE_VALUE) { \
161 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
165 #endif /* MS_WINDOWS */
168 #define CHECK_VALID(err) \
170 if (self->data == NULL) { \
171 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
178 mmap_read_byte_method(mmap_object
*self
,
182 if (self
->pos
< self
->size
) {
183 char value
= self
->data
[self
->pos
];
185 return Py_BuildValue("c", value
);
187 PyErr_SetString(PyExc_ValueError
, "read byte out of range");
193 mmap_read_line_method(mmap_object
*self
,
196 char *start
= self
->data
+self
->pos
;
197 char *eof
= self
->data
+self
->size
;
203 eol
= memchr(start
, '\n', self
->size
- self
->pos
);
207 ++eol
; /* we're interested in the position after the
209 result
= PyString_FromStringAndSize(start
, (eol
- start
));
210 self
->pos
+= (eol
- start
);
215 mmap_read_method(mmap_object
*self
,
218 Py_ssize_t num_bytes
;
222 if (!PyArg_ParseTuple(args
, "n:read", &num_bytes
))
225 /* silently 'adjust' out-of-range requests */
226 if ((self
->pos
+ num_bytes
) > self
->size
) {
227 num_bytes
-= (self
->pos
+num_bytes
) - self
->size
;
229 result
= Py_BuildValue("s#", self
->data
+self
->pos
, num_bytes
);
230 self
->pos
+= num_bytes
;
235 mmap_find_method(mmap_object
*self
,
238 Py_ssize_t start
= self
->pos
;
243 if (!PyArg_ParseTuple(args
, "s#|n:find", &needle
, &len
, &start
)) {
247 char *e
= self
->data
+ self
->size
;
253 else if ((size_t)start
> self
->size
)
256 for (p
= self
->data
+ start
; p
+ len
<= e
; ++p
) {
258 for (i
= 0; i
< len
&& needle
[i
] == p
[i
]; ++i
)
261 return PyInt_FromSsize_t(p
- self
->data
);
264 return PyInt_FromLong(-1);
269 is_writeable(mmap_object
*self
)
271 if (self
->access
!= ACCESS_READ
)
273 PyErr_Format(PyExc_TypeError
, "mmap can't modify a readonly memory map.");
278 is_resizeable(mmap_object
*self
)
280 if ((self
->access
== ACCESS_WRITE
) || (self
->access
== ACCESS_DEFAULT
))
282 PyErr_Format(PyExc_TypeError
,
283 "mmap can't resize a readonly or copy-on-write memory map.");
289 mmap_write_method(mmap_object
*self
,
296 if (!PyArg_ParseTuple(args
, "s#:write", &data
, &length
))
299 if (!is_writeable(self
))
302 if ((self
->pos
+ length
) > self
->size
) {
303 PyErr_SetString(PyExc_ValueError
, "data out of range");
306 memcpy(self
->data
+self
->pos
, data
, length
);
307 self
->pos
= self
->pos
+length
;
313 mmap_write_byte_method(mmap_object
*self
,
319 if (!PyArg_ParseTuple(args
, "c:write_byte", &value
))
322 if (!is_writeable(self
))
324 *(self
->data
+self
->pos
) = value
;
331 mmap_size_method(mmap_object
*self
,
337 if (self
->file_handle
!= INVALID_HANDLE_VALUE
) {
340 low
= GetFileSize(self
->file_handle
, &high
);
341 if (low
== INVALID_FILE_SIZE
) {
342 /* It might be that the function appears to have failed,
343 when indeed its size equals INVALID_FILE_SIZE */
344 DWORD error
= GetLastError();
345 if (error
!= NO_ERROR
)
346 return PyErr_SetFromWindowsErr(error
);
348 if (!high
&& low
< LONG_MAX
)
349 return PyInt_FromLong((long)low
);
350 size
= (((PY_LONG_LONG
)high
)<<32) + low
;
351 return PyLong_FromLongLong(size
);
353 return PyInt_FromSsize_t(self
->size
);
355 #endif /* MS_WINDOWS */
360 if (-1 == fstat(self
->fd
, &buf
)) {
361 PyErr_SetFromErrno(mmap_module_error
);
364 return PyInt_FromSsize_t(buf
.st_size
);
369 /* This assumes that you want the entire file mapped,
370 / and when recreating the map will make the new file
373 / Is this really necessary? This could easily be done
374 / from python by just closing and re-opening with the
379 mmap_resize_method(mmap_object
*self
,
384 if (!PyArg_ParseTuple(args
, "n:resize", &new_size
) ||
385 !is_resizeable(self
)) {
390 DWORD newSizeLow
, newSizeHigh
;
391 /* First, unmap the file view */
392 UnmapViewOfFile(self
->data
);
393 /* Close the mapping object */
394 CloseHandle(self
->map_handle
);
395 /* Move to the desired EOF position */
396 #if SIZEOF_SIZE_T > 4
397 newSizeHigh
= (DWORD
)(new_size
>> 32);
398 newSizeLow
= (DWORD
)(new_size
& 0xFFFFFFFF);
401 newSizeLow
= (DWORD
)new_size
;
403 SetFilePointer(self
->file_handle
,
404 newSizeLow
, &newSizeHigh
, FILE_BEGIN
);
405 /* Change the size of the file */
406 SetEndOfFile(self
->file_handle
);
407 /* Create another mapping object and remap the file view */
408 self
->map_handle
= CreateFileMapping(
415 if (self
->map_handle
!= NULL
) {
416 self
->data
= (char *) MapViewOfFile(self
->map_handle
,
421 if (self
->data
!= NULL
) {
422 self
->size
= new_size
;
426 dwErrCode
= GetLastError();
429 dwErrCode
= GetLastError();
431 PyErr_SetFromWindowsErr(dwErrCode
);
433 #endif /* MS_WINDOWS */
438 PyErr_SetString(PyExc_SystemError
,
439 "mmap: resizing not available--no mremap()");
445 if (ftruncate(self
->fd
, new_size
) == -1) {
446 PyErr_SetFromErrno(mmap_module_error
);
450 #ifdef MREMAP_MAYMOVE
451 newmap
= mremap(self
->data
, self
->size
, new_size
, MREMAP_MAYMOVE
);
453 newmap
= mremap(self
->data
, self
->size
, new_size
, 0);
455 if (newmap
== (void *)-1)
457 PyErr_SetFromErrno(mmap_module_error
);
461 self
->size
= new_size
;
464 #endif /* HAVE_MREMAP */
470 mmap_tell_method(mmap_object
*self
, PyObject
*unused
)
473 return PyInt_FromSize_t(self
->pos
);
477 mmap_flush_method(mmap_object
*self
, PyObject
*args
)
479 Py_ssize_t offset
= 0;
480 Py_ssize_t size
= self
->size
;
482 if (!PyArg_ParseTuple(args
, "|nn:flush", &offset
, &size
))
484 if ((size_t)(offset
+ size
) > self
->size
) {
485 PyErr_SetString(PyExc_ValueError
, "flush values out of range");
489 return PyInt_FromLong((long)
490 FlushViewOfFile(self
->data
+offset
, size
));
491 #endif /* MS_WINDOWS */
493 /* XXX semantics of return value? */
494 /* XXX flags for msync? */
495 if (-1 == msync(self
->data
+ offset
, size
,
498 PyErr_SetFromErrno(mmap_module_error
);
501 return PyInt_FromLong(0);
507 mmap_seek_method(mmap_object
*self
, PyObject
*args
)
512 if (!PyArg_ParseTuple(args
, "n|i:seek", &dist
, &how
))
517 case 0: /* relative to start */
522 case 1: /* relative to current position */
523 if ((Py_ssize_t
)self
->pos
+ dist
< 0)
525 where
= self
->pos
+ dist
;
527 case 2: /* relative to end */
528 if ((Py_ssize_t
)self
->size
+ dist
< 0)
530 where
= self
->size
+ dist
;
533 PyErr_SetString(PyExc_ValueError
, "unknown seek type");
536 if (where
> self
->size
)
544 PyErr_SetString(PyExc_ValueError
, "seek out of range");
549 mmap_move_method(mmap_object
*self
, PyObject
*args
)
551 unsigned long dest
, src
, count
;
553 if (!PyArg_ParseTuple(args
, "kkk:move", &dest
, &src
, &count
) ||
554 !is_writeable(self
)) {
557 /* bounds check the values */
558 if (/* end of source after end of data?? */
559 ((src
+count
) > self
->size
)
561 || (dest
+count
> self
->size
)) {
562 PyErr_SetString(PyExc_ValueError
,
563 "source or destination out of range");
566 memmove(self
->data
+dest
, self
->data
+src
, count
);
573 static struct PyMethodDef mmap_object_methods
[] = {
574 {"close", (PyCFunction
) mmap_close_method
, METH_NOARGS
},
575 {"find", (PyCFunction
) mmap_find_method
, METH_VARARGS
},
576 {"flush", (PyCFunction
) mmap_flush_method
, METH_VARARGS
},
577 {"move", (PyCFunction
) mmap_move_method
, METH_VARARGS
},
578 {"read", (PyCFunction
) mmap_read_method
, METH_VARARGS
},
579 {"read_byte", (PyCFunction
) mmap_read_byte_method
, METH_NOARGS
},
580 {"readline", (PyCFunction
) mmap_read_line_method
, METH_NOARGS
},
581 {"resize", (PyCFunction
) mmap_resize_method
, METH_VARARGS
},
582 {"seek", (PyCFunction
) mmap_seek_method
, METH_VARARGS
},
583 {"size", (PyCFunction
) mmap_size_method
, METH_NOARGS
},
584 {"tell", (PyCFunction
) mmap_tell_method
, METH_NOARGS
},
585 {"write", (PyCFunction
) mmap_write_method
, METH_VARARGS
},
586 {"write_byte", (PyCFunction
) mmap_write_byte_method
, METH_VARARGS
},
587 {NULL
, NULL
} /* sentinel */
590 /* Functions for treating an mmap'ed file as a buffer */
593 mmap_buffer_getreadbuf(mmap_object
*self
, Py_ssize_t index
, const void **ptr
)
597 PyErr_SetString(PyExc_SystemError
,
598 "Accessing non-existent mmap segment");
606 mmap_buffer_getwritebuf(mmap_object
*self
, Py_ssize_t index
, const void **ptr
)
610 PyErr_SetString(PyExc_SystemError
,
611 "Accessing non-existent mmap segment");
614 if (!is_writeable(self
))
621 mmap_buffer_getsegcount(mmap_object
*self
, Py_ssize_t
*lenp
)
630 mmap_buffer_getcharbuffer(mmap_object
*self
, Py_ssize_t index
, const void **ptr
)
633 PyErr_SetString(PyExc_SystemError
,
634 "accessing non-existent buffer segment");
637 *ptr
= (const char *)self
->data
;
642 mmap_object_getattr(mmap_object
*self
, char *name
)
644 return Py_FindMethod(mmap_object_methods
, (PyObject
*)self
, name
);
648 mmap_length(mmap_object
*self
)
655 mmap_item(mmap_object
*self
, Py_ssize_t i
)
658 if (i
< 0 || (size_t)i
>= self
->size
) {
659 PyErr_SetString(PyExc_IndexError
, "mmap index out of range");
662 return PyString_FromStringAndSize(self
->data
+ i
, 1);
666 mmap_slice(mmap_object
*self
, Py_ssize_t ilow
, Py_ssize_t ihigh
)
671 else if ((size_t)ilow
> self
->size
)
677 else if ((size_t)ihigh
> self
->size
)
680 return PyString_FromStringAndSize(self
->data
+ ilow
, ihigh
-ilow
);
684 mmap_subscript(mmap_object
*self
, PyObject
*item
)
687 if (PyIndex_Check(item
)) {
688 Py_ssize_t i
= PyNumber_AsSsize_t(item
, PyExc_IndexError
);
689 if (i
== -1 && PyErr_Occurred())
693 if (i
< 0 || i
> self
->size
) {
694 PyErr_SetString(PyExc_IndexError
,
695 "mmap index out of range");
698 return PyString_FromStringAndSize(self
->data
+ i
, 1);
700 else if (PySlice_Check(item
)) {
701 Py_ssize_t start
, stop
, step
, slicelen
;
703 if (PySlice_GetIndicesEx((PySliceObject
*)item
, self
->size
,
704 &start
, &stop
, &step
, &slicelen
) < 0) {
709 return PyString_FromStringAndSize("", 0);
711 return PyString_FromStringAndSize(self
->data
+ start
,
714 char *result_buf
= (char *)PyMem_Malloc(slicelen
);
718 if (result_buf
== NULL
)
719 return PyErr_NoMemory();
720 for (cur
= start
, i
= 0; i
< slicelen
;
722 result_buf
[i
] = self
->data
[cur
];
724 result
= PyString_FromStringAndSize(result_buf
,
726 PyMem_Free(result_buf
);
731 PyErr_SetString(PyExc_TypeError
,
732 "mmap indices must be integers");
738 mmap_concat(mmap_object
*self
, PyObject
*bb
)
741 PyErr_SetString(PyExc_SystemError
,
742 "mmaps don't support concatenation");
747 mmap_repeat(mmap_object
*self
, Py_ssize_t n
)
750 PyErr_SetString(PyExc_SystemError
,
751 "mmaps don't support repeat operation");
756 mmap_ass_slice(mmap_object
*self
, Py_ssize_t ilow
, Py_ssize_t ihigh
, PyObject
*v
)
763 else if ((size_t)ilow
> self
->size
)
769 else if ((size_t)ihigh
> self
->size
)
773 PyErr_SetString(PyExc_TypeError
,
774 "mmap object doesn't support slice deletion");
777 if (! (PyString_Check(v
)) ) {
778 PyErr_SetString(PyExc_IndexError
,
779 "mmap slice assignment must be a string");
782 if (PyString_Size(v
) != (ihigh
- ilow
)) {
783 PyErr_SetString(PyExc_IndexError
,
784 "mmap slice assignment is wrong size");
787 if (!is_writeable(self
))
789 buf
= PyString_AsString(v
);
790 memcpy(self
->data
+ ilow
, buf
, ihigh
-ilow
);
795 mmap_ass_item(mmap_object
*self
, Py_ssize_t i
, PyObject
*v
)
800 if (i
< 0 || (size_t)i
>= self
->size
) {
801 PyErr_SetString(PyExc_IndexError
, "mmap index out of range");
805 PyErr_SetString(PyExc_TypeError
,
806 "mmap object doesn't support item deletion");
809 if (! (PyString_Check(v
) && PyString_Size(v
)==1) ) {
810 PyErr_SetString(PyExc_IndexError
,
811 "mmap assignment must be single-character string");
814 if (!is_writeable(self
))
816 buf
= PyString_AsString(v
);
817 self
->data
[i
] = buf
[0];
822 mmap_ass_subscript(mmap_object
*self
, PyObject
*item
, PyObject
*value
)
826 if (PyIndex_Check(item
)) {
827 Py_ssize_t i
= PyNumber_AsSsize_t(item
, PyExc_IndexError
);
830 if (i
== -1 && PyErr_Occurred())
834 if (i
< 0 || i
> self
->size
) {
835 PyErr_SetString(PyExc_IndexError
,
836 "mmap index out of range");
840 PyErr_SetString(PyExc_TypeError
,
841 "mmap object doesn't support item deletion");
844 if (!PyString_Check(value
) || PyString_Size(value
) != 1) {
845 PyErr_SetString(PyExc_IndexError
,
846 "mmap assignment must be single-character string");
849 if (!is_writeable(self
))
851 buf
= PyString_AsString(value
);
852 self
->data
[i
] = buf
[0];
855 else if (PySlice_Check(item
)) {
856 Py_ssize_t start
, stop
, step
, slicelen
;
858 if (PySlice_GetIndicesEx((PySliceObject
*)item
,
859 self
->size
, &start
, &stop
,
860 &step
, &slicelen
) < 0) {
864 PyErr_SetString(PyExc_TypeError
,
865 "mmap object doesn't support slice deletion");
868 if (!PyString_Check(value
)) {
869 PyErr_SetString(PyExc_IndexError
,
870 "mmap slice assignment must be a string");
873 if (PyString_Size(value
) != slicelen
) {
874 PyErr_SetString(PyExc_IndexError
,
875 "mmap slice assignment is wrong size");
878 if (!is_writeable(self
))
883 else if (step
== 1) {
884 const char *buf
= PyString_AsString(value
);
888 memcpy(self
->data
+ start
, buf
, slicelen
);
893 const char *buf
= PyString_AsString(value
);
897 for (cur
= start
, i
= 0; i
< slicelen
;
899 self
->data
[cur
] = buf
[i
];
905 PyErr_SetString(PyExc_TypeError
,
906 "mmap indices must be integer");
911 static PySequenceMethods mmap_as_sequence
= {
912 (lenfunc
)mmap_length
, /*sq_length*/
913 (binaryfunc
)mmap_concat
, /*sq_concat*/
914 (ssizeargfunc
)mmap_repeat
, /*sq_repeat*/
915 (ssizeargfunc
)mmap_item
, /*sq_item*/
916 (ssizessizeargfunc
)mmap_slice
, /*sq_slice*/
917 (ssizeobjargproc
)mmap_ass_item
, /*sq_ass_item*/
918 (ssizessizeobjargproc
)mmap_ass_slice
, /*sq_ass_slice*/
921 static PyMappingMethods mmap_as_mapping
= {
922 (lenfunc
)mmap_length
,
923 (binaryfunc
)mmap_subscript
,
924 (objobjargproc
)mmap_ass_subscript
,
927 static PyBufferProcs mmap_as_buffer
= {
928 (readbufferproc
)mmap_buffer_getreadbuf
,
929 (writebufferproc
)mmap_buffer_getwritebuf
,
930 (segcountproc
)mmap_buffer_getsegcount
,
931 (charbufferproc
)mmap_buffer_getcharbuffer
,
934 static PyTypeObject mmap_object_type
= {
935 PyVarObject_HEAD_INIT(0, 0) /* patched in module init */
936 "mmap.mmap", /* tp_name */
937 sizeof(mmap_object
), /* tp_size */
940 (destructor
) mmap_object_dealloc
, /* tp_dealloc */
942 (getattrfunc
) mmap_object_getattr
, /* tp_getattr */
946 0, /* tp_as_number */
947 &mmap_as_sequence
, /*tp_as_sequence*/
948 &mmap_as_mapping
, /*tp_as_mapping*/
954 &mmap_as_buffer
, /*tp_as_buffer*/
955 Py_TPFLAGS_HAVE_GETCHARBUFFER
, /*tp_flags*/
960 /* extract the map size from the given PyObject
962 Returns -1 on error, with an appropriate Python exception raised. On
963 success, the map size is returned. */
965 _GetMapSize(PyObject
*o
)
967 if (PyIndex_Check(o
)) {
968 Py_ssize_t i
= PyNumber_AsSsize_t(o
, PyExc_OverflowError
);
969 if (i
==-1 && PyErr_Occurred())
972 PyErr_SetString(PyExc_OverflowError
,
973 "memory mapped size must be positive");
979 PyErr_SetString(PyExc_TypeError
, "map size must be an integral value");
985 new_mmap_object(PyObject
*self
, PyObject
*args
, PyObject
*kwdict
)
991 PyObject
*map_size_obj
= NULL
;
993 int fd
, flags
= MAP_SHARED
, prot
= PROT_WRITE
| PROT_READ
;
995 int access
= (int)ACCESS_DEFAULT
;
996 static char *keywords
[] = {"fileno", "length",
1000 if (!PyArg_ParseTupleAndKeywords(args
, kwdict
, "iO|iii", keywords
,
1001 &fd
, &map_size_obj
, &flags
, &prot
,
1004 map_size
= _GetMapSize(map_size_obj
);
1008 if ((access
!= (int)ACCESS_DEFAULT
) &&
1009 ((flags
!= MAP_SHARED
) || (prot
!= (PROT_WRITE
| PROT_READ
))))
1010 return PyErr_Format(PyExc_ValueError
,
1011 "mmap can't specify both access and flags, prot.");
1012 switch ((access_mode
)access
) {
1019 prot
= PROT_READ
| PROT_WRITE
;
1022 flags
= MAP_PRIVATE
;
1023 prot
= PROT_READ
| PROT_WRITE
;
1025 case ACCESS_DEFAULT
:
1026 /* use the specified or default values of flags and prot */
1029 return PyErr_Format(PyExc_ValueError
,
1030 "mmap invalid access parameter.");
1035 /* on OpenVMS we must ensure that all bytes are written to the file */
1038 if (fstat(fd
, &st
) == 0 && S_ISREG(st
.st_mode
)) {
1039 if (map_size
== 0) {
1040 map_size
= st
.st_size
;
1041 } else if ((size_t)map_size
> st
.st_size
) {
1042 PyErr_SetString(PyExc_ValueError
,
1043 "mmap length is greater than file size");
1048 m_obj
= PyObject_New(mmap_object
, &mmap_object_type
);
1049 if (m_obj
== NULL
) {return NULL
;}
1051 m_obj
->size
= (size_t) map_size
;
1052 m_obj
->pos
= (size_t) 0;
1055 /* Assume the caller wants to map anonymous memory.
1056 This is the same behaviour as Windows. mmap.mmap(-1, size)
1057 on both Windows and Unix map anonymous memory.
1059 #ifdef MAP_ANONYMOUS
1060 /* BSD way to map anonymous memory */
1061 flags
|= MAP_ANONYMOUS
;
1063 /* SVR4 method to map anonymous memory is to open /dev/zero */
1064 fd
= devzero
= open("/dev/zero", O_RDWR
);
1065 if (devzero
== -1) {
1067 PyErr_SetFromErrno(mmap_module_error
);
1072 m_obj
->fd
= dup(fd
);
1073 if (m_obj
->fd
== -1) {
1075 PyErr_SetFromErrno(mmap_module_error
);
1080 m_obj
->data
= mmap(NULL
, map_size
,
1084 if (devzero
!= -1) {
1088 if (m_obj
->data
== (char *)-1) {
1091 PyErr_SetFromErrno(mmap_module_error
);
1094 m_obj
->access
= (access_mode
)access
;
1095 return (PyObject
*)m_obj
;
1101 new_mmap_object(PyObject
*self
, PyObject
*args
, PyObject
*kwdict
)
1104 PyObject
*map_size_obj
= NULL
;
1105 Py_ssize_t map_size
;
1106 DWORD size_hi
; /* upper 32 bits of m_obj->size */
1107 DWORD size_lo
; /* lower 32 bits of m_obj->size */
1112 int access
= (access_mode
)ACCESS_DEFAULT
;
1113 DWORD flProtect
, dwDesiredAccess
;
1114 static char *keywords
[] = { "fileno", "length",
1118 if (!PyArg_ParseTupleAndKeywords(args
, kwdict
, "iO|zi", keywords
,
1119 &fileno
, &map_size_obj
,
1120 &tagname
, &access
)) {
1124 switch((access_mode
)access
) {
1126 flProtect
= PAGE_READONLY
;
1127 dwDesiredAccess
= FILE_MAP_READ
;
1129 case ACCESS_DEFAULT
: case ACCESS_WRITE
:
1130 flProtect
= PAGE_READWRITE
;
1131 dwDesiredAccess
= FILE_MAP_WRITE
;
1134 flProtect
= PAGE_WRITECOPY
;
1135 dwDesiredAccess
= FILE_MAP_COPY
;
1138 return PyErr_Format(PyExc_ValueError
,
1139 "mmap invalid access parameter.");
1142 map_size
= _GetMapSize(map_size_obj
);
1146 /* assume -1 and 0 both mean invalid filedescriptor
1147 to 'anonymously' map memory.
1148 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1149 XXX: Should this code be added?
1151 PyErr_Warn(PyExc_DeprecationWarning,
1152 "don't use 0 for anonymous memory");
1154 if (fileno
!= -1 && fileno
!= 0) {
1155 fh
= (HANDLE
)_get_osfhandle(fileno
);
1156 if (fh
==(HANDLE
)-1) {
1157 PyErr_SetFromErrno(mmap_module_error
);
1160 /* Win9x appears to need us seeked to zero */
1161 lseek(fileno
, 0, SEEK_SET
);
1164 m_obj
= PyObject_New(mmap_object
, &mmap_object_type
);
1167 /* Set every field to an invalid marker, so we can safely
1168 destruct the object in the face of failure */
1170 m_obj
->file_handle
= INVALID_HANDLE_VALUE
;
1171 m_obj
->map_handle
= INVALID_HANDLE_VALUE
;
1172 m_obj
->tagname
= NULL
;
1175 /* It is necessary to duplicate the handle, so the
1176 Python code can close it on us */
1177 if (!DuplicateHandle(
1178 GetCurrentProcess(), /* source process handle */
1179 fh
, /* handle to be duplicated */
1180 GetCurrentProcess(), /* target proc handle */
1181 (LPHANDLE
)&m_obj
->file_handle
, /* result */
1182 0, /* access - ignored due to options value */
1183 FALSE
, /* inherited by child processes? */
1184 DUPLICATE_SAME_ACCESS
)) { /* options */
1185 dwErr
= GetLastError();
1187 PyErr_SetFromWindowsErr(dwErr
);
1192 low
= GetFileSize(fh
, &high
);
1193 /* low might just happen to have the value INVALID_FILE_SIZE;
1194 so we need to check the last error also. */
1195 if (low
== INVALID_FILE_SIZE
&&
1196 (dwErr
= GetLastError()) != NO_ERROR
) {
1198 return PyErr_SetFromWindowsErr(dwErr
);
1201 #if SIZEOF_SIZE_T > 4
1202 m_obj
->size
= (((size_t)high
)<<32) + low
;
1205 /* File is too large to map completely */
1206 m_obj
->size
= (size_t)-1;
1211 m_obj
->size
= map_size
;
1215 m_obj
->size
= map_size
;
1218 /* set the initial position */
1219 m_obj
->pos
= (size_t) 0;
1221 /* set the tag name */
1222 if (tagname
!= NULL
&& *tagname
!= '\0') {
1223 m_obj
->tagname
= PyMem_Malloc(strlen(tagname
)+1);
1224 if (m_obj
->tagname
== NULL
) {
1229 strcpy(m_obj
->tagname
, tagname
);
1232 m_obj
->tagname
= NULL
;
1234 m_obj
->access
= (access_mode
)access
;
1235 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
1236 * more than 4 bytes, we need to break it apart. Else (size_t
1237 * consumes 4 bytes), C doesn't define what happens if we shift
1238 * right by 32, so we need different code.
1240 #if SIZEOF_SIZE_T > 4
1241 size_hi
= (DWORD
)(m_obj
->size
>> 32);
1242 size_lo
= (DWORD
)(m_obj
->size
& 0xFFFFFFFF);
1245 size_lo
= (DWORD
)m_obj
->size
;
1247 m_obj
->map_handle
= CreateFileMapping(m_obj
->file_handle
,
1253 if (m_obj
->map_handle
!= NULL
) {
1254 m_obj
->data
= (char *) MapViewOfFile(m_obj
->map_handle
,
1259 if (m_obj
->data
!= NULL
)
1260 return (PyObject
*)m_obj
;
1262 dwErr
= GetLastError();
1264 dwErr
= GetLastError();
1266 PyErr_SetFromWindowsErr(dwErr
);
1269 #endif /* MS_WINDOWS */
1271 /* List of functions exported by this module */
1272 static struct PyMethodDef mmap_functions
[] = {
1273 {"mmap", (PyCFunction
) new_mmap_object
,
1274 METH_VARARGS
|METH_KEYWORDS
},
1275 {NULL
, NULL
} /* Sentinel */
1279 setint(PyObject
*d
, const char *name
, long value
)
1281 PyObject
*o
= PyInt_FromLong(value
);
1282 if (o
&& PyDict_SetItemString(d
, name
, o
) == 0) {
1290 PyObject
*dict
, *module
;
1292 /* Patch the object type */
1293 Py_Type(&mmap_object_type
) = &PyType_Type
;
1295 module
= Py_InitModule("mmap", mmap_functions
);
1298 dict
= PyModule_GetDict(module
);
1301 mmap_module_error
= PyExc_EnvironmentError
;
1302 PyDict_SetItemString(dict
, "error", mmap_module_error
);
1304 setint(dict
, "PROT_EXEC", PROT_EXEC
);
1307 setint(dict
, "PROT_READ", PROT_READ
);
1310 setint(dict
, "PROT_WRITE", PROT_WRITE
);
1314 setint(dict
, "MAP_SHARED", MAP_SHARED
);
1317 setint(dict
, "MAP_PRIVATE", MAP_PRIVATE
);
1319 #ifdef MAP_DENYWRITE
1320 setint(dict
, "MAP_DENYWRITE", MAP_DENYWRITE
);
1322 #ifdef MAP_EXECUTABLE
1323 setint(dict
, "MAP_EXECUTABLE", MAP_EXECUTABLE
);
1325 #ifdef MAP_ANONYMOUS
1326 setint(dict
, "MAP_ANON", MAP_ANONYMOUS
);
1327 setint(dict
, "MAP_ANONYMOUS", MAP_ANONYMOUS
);
1330 setint(dict
, "PAGESIZE", (long)my_getpagesize());
1332 setint(dict
, "ACCESS_READ", ACCESS_READ
);
1333 setint(dict
, "ACCESS_WRITE", ACCESS_WRITE
);
1334 setint(dict
, "ACCESS_COPY", ACCESS_COPY
);