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 / Note: This module currently only deals with 32-bit file
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.
44 /* This is missing e.g. on SunOS 4.1.4 */
48 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
52 return sysconf(_SC_PAGESIZE
);
55 #define my_getpagesize getpagesize
61 #include <sys/types.h>
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_WIN32 */
108 if (m_obj
->data
!=NULL
) {
109 msync(m_obj
->data
, m_obj
->size
, MS_SYNC
);
110 munmap(m_obj
->data
, m_obj
->size
);
118 mmap_close_method(mmap_object
*self
, PyObject
*args
)
120 if (!PyArg_ParseTuple(args
, ":close"))
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_WIN32 */
145 munmap(self
->data
, self
->size
);
154 #define CHECK_VALID(err) \
156 if (!self->map_handle) { \
157 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
161 #endif /* MS_WIN32 */
164 #define CHECK_VALID(err) \
166 if (self->data == NULL) { \
167 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
174 mmap_read_byte_method(mmap_object
*self
,
178 if (!PyArg_ParseTuple(args
, ":read_byte"))
180 if (self
->pos
< self
->size
) {
181 char value
= self
->data
[self
->pos
];
183 return Py_BuildValue("c", value
);
185 PyErr_SetString (PyExc_ValueError
, "read byte out of range");
191 mmap_read_line_method(mmap_object
*self
,
194 char *start
= self
->data
+self
->pos
;
195 char *eof
= self
->data
+self
->size
;
200 if (!PyArg_ParseTuple(args
, ":readline"))
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
,
222 if (!PyArg_ParseTuple(args
, "l: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 long start
= self
->pos
;
243 if (!PyArg_ParseTuple (args
, "s#|l:find", &needle
, &len
, &start
)) {
247 char *e
= self
->data
+ self
->size
;
253 else if ((size_t)start
> self
->size
)
255 p
= self
->data
+ start
;
260 while ((s
<e
) && (*n
) && !(*s
-*n
)) {
264 return Py_BuildValue (
266 (long) (p
- self
->data
));
270 return Py_BuildValue ("l", (long) -1);
275 is_writeable(mmap_object
*self
)
277 if (self
->access
!= ACCESS_READ
)
279 PyErr_Format(PyExc_TypeError
, "mmap can't modify a readonly memory map.");
284 is_resizeable(mmap_object
*self
)
286 if ((self
->access
== ACCESS_WRITE
) || (self
->access
== ACCESS_DEFAULT
))
288 PyErr_Format(PyExc_TypeError
,
289 "mmap can't resize a readonly or copy-on-write memory map.");
295 mmap_write_method(mmap_object
*self
,
302 if (!PyArg_ParseTuple (args
, "s#:write", &data
, &length
))
305 if (!is_writeable(self
))
308 if ((self
->pos
+ length
) > self
->size
) {
309 PyErr_SetString (PyExc_ValueError
, "data out of range");
312 memcpy (self
->data
+self
->pos
, data
, length
);
313 self
->pos
= self
->pos
+length
;
319 mmap_write_byte_method(mmap_object
*self
,
325 if (!PyArg_ParseTuple (args
, "c:write_byte", &value
))
328 if (!is_writeable(self
))
330 *(self
->data
+self
->pos
) = value
;
337 mmap_size_method(mmap_object
*self
,
341 if (!PyArg_ParseTuple(args
, ":size"))
345 if (self
->file_handle
!= INVALID_HANDLE_VALUE
) {
346 return (Py_BuildValue (
348 GetFileSize (self
->file_handle
, NULL
)));
350 return (Py_BuildValue ("l", (long) self
->size
) );
352 #endif /* MS_WIN32 */
357 if (-1 == fstat(self
->fd
, &buf
)) {
358 PyErr_SetFromErrno(mmap_module_error
);
361 return (Py_BuildValue ("l", (long) buf
.st_size
) );
366 /* This assumes that you want the entire file mapped,
367 / and when recreating the map will make the new file
370 / Is this really necessary? This could easily be done
371 / from python by just closing and re-opening with the
376 mmap_resize_method(mmap_object
*self
,
379 unsigned long new_size
;
381 if (!PyArg_ParseTuple (args
, "l:resize", &new_size
) ||
382 !is_resizeable(self
)) {
387 /* First, unmap the file view */
388 UnmapViewOfFile (self
->data
);
389 /* Close the mapping object */
390 CloseHandle (self
->map_handle
);
391 /* Move to the desired EOF position */
392 SetFilePointer (self
->file_handle
,
393 new_size
, NULL
, FILE_BEGIN
);
394 /* Change the size of the file */
395 SetEndOfFile (self
->file_handle
);
396 /* Create another mapping object and remap the file view */
397 self
->map_handle
= CreateFileMapping (
404 if (self
->map_handle
!= NULL
) {
405 self
->data
= (char *) MapViewOfFile (self
->map_handle
,
410 if (self
->data
!= NULL
) {
411 self
->size
= new_size
;
415 dwErrCode
= GetLastError();
418 dwErrCode
= GetLastError();
420 PyErr_SetFromWindowsErr(dwErrCode
);
422 #endif /* MS_WIN32 */
427 PyErr_SetString(PyExc_SystemError
,
428 "mmap: resizing not available--no mremap()");
434 #ifdef MREMAP_MAYMOVE
435 newmap
= mremap(self
->data
, self
->size
, new_size
, MREMAP_MAYMOVE
);
437 newmap
= mremap(self
->data
, self
->size
, new_size
, 0);
439 if (newmap
== (void *)-1)
441 PyErr_SetFromErrno(mmap_module_error
);
445 self
->size
= new_size
;
448 #endif /* HAVE_MREMAP */
454 mmap_tell_method(mmap_object
*self
, PyObject
*args
)
457 if (!PyArg_ParseTuple(args
, ":tell"))
459 return (Py_BuildValue ("l", (long) self
->pos
) );
463 mmap_flush_method(mmap_object
*self
, PyObject
*args
)
466 size_t size
= self
->size
;
468 if (!PyArg_ParseTuple (args
, "|ll:flush", &offset
, &size
)) {
470 } else if ((offset
+ size
) > self
->size
) {
471 PyErr_SetString (PyExc_ValueError
,
472 "flush values out of range");
476 return (Py_BuildValue("l", (long)
477 FlushViewOfFile(self
->data
+offset
, size
)));
478 #endif /* MS_WIN32 */
480 /* XXX semantics of return value? */
481 /* XXX flags for msync? */
482 if (-1 == msync(self
->data
+ offset
, size
,
485 PyErr_SetFromErrno(mmap_module_error
);
488 return Py_BuildValue ("l", (long) 0);
494 mmap_seek_method(mmap_object
*self
, PyObject
*args
)
499 if (!PyArg_ParseTuple (args
, "i|i:seek", &dist
, &how
)) {
504 case 0: /* relative to start */
509 case 1: /* relative to current position */
510 if ((int)self
->pos
+ dist
< 0)
512 where
= self
->pos
+ dist
;
514 case 2: /* relative to end */
515 if ((int)self
->size
+ dist
< 0)
517 where
= self
->size
+ dist
;
520 PyErr_SetString (PyExc_ValueError
,
521 "unknown seek type");
524 if (where
> self
->size
)
532 PyErr_SetString (PyExc_ValueError
, "seek out of range");
537 mmap_move_method(mmap_object
*self
, PyObject
*args
)
539 unsigned long dest
, src
, count
;
541 if (!PyArg_ParseTuple (args
, "iii:move", &dest
, &src
, &count
) ||
542 !is_writeable(self
)) {
545 /* bounds check the values */
546 if (/* end of source after end of data?? */
547 ((src
+count
) > self
->size
)
549 || (dest
+count
> self
->size
)) {
550 PyErr_SetString (PyExc_ValueError
,
551 "source or destination out of range");
554 memmove (self
->data
+dest
, self
->data
+src
, count
);
561 static struct PyMethodDef mmap_object_methods
[] = {
562 {"close", (PyCFunction
) mmap_close_method
, 1},
563 {"find", (PyCFunction
) mmap_find_method
, 1},
564 {"flush", (PyCFunction
) mmap_flush_method
, 1},
565 {"move", (PyCFunction
) mmap_move_method
, 1},
566 {"read", (PyCFunction
) mmap_read_method
, 1},
567 {"read_byte", (PyCFunction
) mmap_read_byte_method
, 1},
568 {"readline", (PyCFunction
) mmap_read_line_method
, 1},
569 {"resize", (PyCFunction
) mmap_resize_method
, 1},
570 {"seek", (PyCFunction
) mmap_seek_method
, 1},
571 {"size", (PyCFunction
) mmap_size_method
, 1},
572 {"tell", (PyCFunction
) mmap_tell_method
, 1},
573 {"write", (PyCFunction
) mmap_write_method
, 1},
574 {"write_byte", (PyCFunction
) mmap_write_byte_method
, 1},
575 {NULL
, NULL
} /* sentinel */
578 /* Functions for treating an mmap'ed file as a buffer */
581 mmap_buffer_getreadbuf(mmap_object
*self
, int index
, const void **ptr
)
585 PyErr_SetString(PyExc_SystemError
,
586 "Accessing non-existent mmap segment");
594 mmap_buffer_getwritebuf(mmap_object
*self
, int index
, const void **ptr
)
598 PyErr_SetString(PyExc_SystemError
,
599 "Accessing non-existent mmap segment");
602 if (!is_writeable(self
))
609 mmap_buffer_getsegcount(mmap_object
*self
, int *lenp
)
618 mmap_buffer_getcharbuffer(mmap_object
*self
, int index
, const void **ptr
)
621 PyErr_SetString(PyExc_SystemError
,
622 "accessing non-existent buffer segment");
625 *ptr
= (const char *)self
->data
;
630 mmap_object_getattr(mmap_object
*self
, char *name
)
632 return Py_FindMethod (mmap_object_methods
, (PyObject
*)self
, name
);
636 mmap_length(mmap_object
*self
)
643 mmap_item(mmap_object
*self
, int i
)
646 if (i
< 0 || (size_t)i
>= self
->size
) {
647 PyErr_SetString(PyExc_IndexError
, "mmap index out of range");
650 return PyString_FromStringAndSize(self
->data
+ i
, 1);
654 mmap_slice(mmap_object
*self
, int ilow
, int ihigh
)
659 else if ((size_t)ilow
> self
->size
)
665 else if ((size_t)ihigh
> self
->size
)
668 return PyString_FromStringAndSize(self
->data
+ ilow
, ihigh
-ilow
);
672 mmap_concat(mmap_object
*self
, PyObject
*bb
)
675 PyErr_SetString(PyExc_SystemError
,
676 "mmaps don't support concatenation");
681 mmap_repeat(mmap_object
*self
, int n
)
684 PyErr_SetString(PyExc_SystemError
,
685 "mmaps don't support repeat operation");
690 mmap_ass_slice(mmap_object
*self
, int ilow
, int ihigh
, PyObject
*v
)
697 else if ((size_t)ilow
> self
->size
)
703 else if ((size_t)ihigh
> self
->size
)
707 PyErr_SetString(PyExc_TypeError
,
708 "mmap object doesn't support slice deletion");
711 if (! (PyString_Check(v
)) ) {
712 PyErr_SetString(PyExc_IndexError
,
713 "mmap slice assignment must be a string");
716 if ( PyString_Size(v
) != (ihigh
- ilow
) ) {
717 PyErr_SetString(PyExc_IndexError
,
718 "mmap slice assignment is wrong size");
721 if (!is_writeable(self
))
723 buf
= PyString_AsString(v
);
724 memcpy(self
->data
+ ilow
, buf
, ihigh
-ilow
);
729 mmap_ass_item(mmap_object
*self
, int i
, PyObject
*v
)
734 if (i
< 0 || (size_t)i
>= self
->size
) {
735 PyErr_SetString(PyExc_IndexError
, "mmap index out of range");
739 PyErr_SetString(PyExc_TypeError
,
740 "mmap object doesn't support item deletion");
743 if (! (PyString_Check(v
) && PyString_Size(v
)==1) ) {
744 PyErr_SetString(PyExc_IndexError
,
745 "mmap assignment must be single-character string");
748 if (!is_writeable(self
))
750 buf
= PyString_AsString(v
);
751 self
->data
[i
] = buf
[0];
755 static PySequenceMethods mmap_as_sequence
= {
756 (inquiry
)mmap_length
, /*sq_length*/
757 (binaryfunc
)mmap_concat
, /*sq_concat*/
758 (intargfunc
)mmap_repeat
, /*sq_repeat*/
759 (intargfunc
)mmap_item
, /*sq_item*/
760 (intintargfunc
)mmap_slice
, /*sq_slice*/
761 (intobjargproc
)mmap_ass_item
, /*sq_ass_item*/
762 (intintobjargproc
)mmap_ass_slice
, /*sq_ass_slice*/
765 static PyBufferProcs mmap_as_buffer
= {
766 (getreadbufferproc
)mmap_buffer_getreadbuf
,
767 (getwritebufferproc
)mmap_buffer_getwritebuf
,
768 (getsegcountproc
)mmap_buffer_getsegcount
,
769 (getcharbufferproc
)mmap_buffer_getcharbuffer
,
772 static PyTypeObject mmap_object_type
= {
773 PyObject_HEAD_INIT(0) /* patched in module init */
775 "mmap.mmap", /* tp_name */
776 sizeof(mmap_object
), /* tp_size */
779 (destructor
) mmap_object_dealloc
, /* tp_dealloc */
781 (getattrfunc
) mmap_object_getattr
, /* tp_getattr */
785 0, /* tp_as_number */
786 &mmap_as_sequence
, /*tp_as_sequence*/
793 &mmap_as_buffer
, /*tp_as_buffer*/
794 Py_TPFLAGS_HAVE_GETCHARBUFFER
, /*tp_flags*/
799 /* extract the map size from the given PyObject
801 The map size is restricted to [0, INT_MAX] because this is the current
802 Python limitation on object sizes. Although the mmap object *could* handle
803 a larger map size, there is no point because all the useful operations
804 (len(), slicing(), sequence indexing) are limited by a C int.
806 Returns -1 on error, with an appropriate Python exception raised. On
807 success, the map size is returned. */
809 _GetMapSize(PyObject
*o
)
811 if (PyInt_Check(o
)) {
812 long i
= PyInt_AsLong(o
);
813 if (PyErr_Occurred())
821 else if (PyLong_Check(o
)) {
822 long i
= PyLong_AsLong(o
);
823 if (PyErr_Occurred()) {
824 /* yes negative overflow is mistaken for positive overflow
825 but not worth the trouble to check sign of 'i' */
826 if (PyErr_ExceptionMatches(PyExc_OverflowError
))
838 PyErr_SetString(PyExc_TypeError
,
839 "map size must be an integral value");
844 PyErr_SetString(PyExc_OverflowError
,
845 "memory mapped size must be positive");
849 PyErr_SetString(PyExc_OverflowError
,
850 "memory mapped size is too large (limited by C int)");
856 new_mmap_object(PyObject
*self
, PyObject
*args
, PyObject
*kwdict
)
859 PyObject
*map_size_obj
= NULL
;
861 int fd
, flags
= MAP_SHARED
, prot
= PROT_WRITE
| PROT_READ
;
862 access_mode access
= ACCESS_DEFAULT
;
863 char *keywords
[] = {"fileno", "length",
867 if (!PyArg_ParseTupleAndKeywords(args
, kwdict
, "iO|iii", keywords
,
868 &fd
, &map_size_obj
, &flags
, &prot
, &access
))
870 map_size
= _GetMapSize(map_size_obj
);
874 if ((access
!= ACCESS_DEFAULT
) &&
875 ((flags
!= MAP_SHARED
) || ( prot
!= (PROT_WRITE
| PROT_READ
))))
876 return PyErr_Format(PyExc_ValueError
,
877 "mmap can't specify both access and flags, prot.");
885 prot
= PROT_READ
| PROT_WRITE
;
889 prot
= PROT_READ
| PROT_WRITE
;
892 /* use the specified or default values of flags and prot */
895 return PyErr_Format(PyExc_ValueError
,
896 "mmap invalid access parameter.");
899 m_obj
= PyObject_New (mmap_object
, &mmap_object_type
);
900 if (m_obj
== NULL
) {return NULL
;}
901 m_obj
->size
= (size_t) map_size
;
902 m_obj
->pos
= (size_t) 0;
904 m_obj
->data
= mmap(NULL
, map_size
,
907 if (m_obj
->data
== (char *)-1) {
909 PyErr_SetFromErrno(mmap_module_error
);
912 m_obj
->access
= access
;
913 return (PyObject
*)m_obj
;
919 new_mmap_object(PyObject
*self
, PyObject
*args
, PyObject
*kwdict
)
922 PyObject
*map_size_obj
= NULL
;
928 access_mode access
= ACCESS_DEFAULT
;
929 DWORD flProtect
, dwDesiredAccess
;
930 char *keywords
[] = { "fileno", "length",
934 if (!PyArg_ParseTupleAndKeywords(args
, kwdict
, "iO|zi", keywords
,
935 &fileno
, &map_size_obj
,
936 &tagname
, &access
)) {
942 flProtect
= PAGE_READONLY
;
943 dwDesiredAccess
= FILE_MAP_READ
;
945 case ACCESS_DEFAULT
: case ACCESS_WRITE
:
946 flProtect
= PAGE_READWRITE
;
947 dwDesiredAccess
= FILE_MAP_WRITE
;
950 flProtect
= PAGE_WRITECOPY
;
951 dwDesiredAccess
= FILE_MAP_COPY
;
954 return PyErr_Format(PyExc_ValueError
,
955 "mmap invalid access parameter.");
958 map_size
= _GetMapSize(map_size_obj
);
962 /* if an actual filename has been specified */
964 fh
= (HANDLE
)_get_osfhandle(fileno
);
965 if (fh
==(HANDLE
)-1) {
966 PyErr_SetFromErrno(mmap_module_error
);
969 /* Win9x appears to need us seeked to zero */
970 fseek(&_iob
[fileno
], 0, SEEK_SET
);
973 m_obj
= PyObject_New (mmap_object
, &mmap_object_type
);
976 /* Set every field to an invalid marker, so we can safely
977 destruct the object in the face of failure */
979 m_obj
->file_handle
= INVALID_HANDLE_VALUE
;
980 m_obj
->map_handle
= INVALID_HANDLE_VALUE
;
981 m_obj
->tagname
= NULL
;
984 /* It is necessary to duplicate the handle, so the
985 Python code can close it on us */
986 if (!DuplicateHandle(
987 GetCurrentProcess(), /* source process handle */
988 fh
, /* handle to be duplicated */
989 GetCurrentProcess(), /* target proc handle */
990 (LPHANDLE
)&m_obj
->file_handle
, /* result */
991 0, /* access - ignored due to options value */
992 FALSE
, /* inherited by child processes? */
993 DUPLICATE_SAME_ACCESS
)) { /* options */
994 dwErr
= GetLastError();
996 PyErr_SetFromWindowsErr(dwErr
);
1000 m_obj
->size
= GetFileSize (fh
, NULL
);
1002 m_obj
->size
= map_size
;
1006 m_obj
->size
= map_size
;
1009 /* set the initial position */
1010 m_obj
->pos
= (size_t) 0;
1012 /* set the tag name */
1013 if (tagname
!= NULL
&& *tagname
!= '\0') {
1014 m_obj
->tagname
= PyMem_Malloc(strlen(tagname
)+1);
1015 if (m_obj
->tagname
== NULL
) {
1020 strcpy(m_obj
->tagname
, tagname
);
1023 m_obj
->tagname
= NULL
;
1025 m_obj
->access
= access
;
1026 m_obj
->map_handle
= CreateFileMapping (m_obj
->file_handle
,
1032 if (m_obj
->map_handle
!= NULL
) {
1033 m_obj
->data
= (char *) MapViewOfFile (m_obj
->map_handle
,
1038 if (m_obj
->data
!= NULL
) {
1039 return ((PyObject
*) m_obj
);
1041 dwErr
= GetLastError();
1044 dwErr
= GetLastError();
1047 PyErr_SetFromWindowsErr(dwErr
);
1050 #endif /* MS_WIN32 */
1052 /* List of functions exported by this module */
1053 static struct PyMethodDef mmap_functions
[] = {
1054 {"mmap", (PyCFunction
) new_mmap_object
,
1055 METH_VARARGS
|METH_KEYWORDS
},
1056 {NULL
, NULL
} /* Sentinel */
1062 PyObject
*dict
, *module
;
1064 /* Patch the object type */
1065 mmap_object_type
.ob_type
= &PyType_Type
;
1067 module
= Py_InitModule ("mmap", mmap_functions
);
1068 dict
= PyModule_GetDict (module
);
1069 mmap_module_error
= PyExc_EnvironmentError
;
1070 Py_INCREF(mmap_module_error
);
1071 PyDict_SetItemString (dict
, "error", mmap_module_error
);
1073 PyDict_SetItemString (dict
, "PROT_EXEC", PyInt_FromLong(PROT_EXEC
) );
1076 PyDict_SetItemString (dict
, "PROT_READ", PyInt_FromLong(PROT_READ
) );
1079 PyDict_SetItemString (dict
, "PROT_WRITE", PyInt_FromLong(PROT_WRITE
) );
1083 PyDict_SetItemString (dict
, "MAP_SHARED", PyInt_FromLong(MAP_SHARED
) );
1086 PyDict_SetItemString (dict
, "MAP_PRIVATE",
1087 PyInt_FromLong(MAP_PRIVATE
) );
1089 #ifdef MAP_DENYWRITE
1090 PyDict_SetItemString (dict
, "MAP_DENYWRITE",
1091 PyInt_FromLong(MAP_DENYWRITE
) );
1093 #ifdef MAP_EXECUTABLE
1094 PyDict_SetItemString (dict
, "MAP_EXECUTABLE",
1095 PyInt_FromLong(MAP_EXECUTABLE
) );
1098 PyDict_SetItemString (dict
, "MAP_ANON", PyInt_FromLong(MAP_ANON
) );
1099 PyDict_SetItemString (dict
, "MAP_ANONYMOUS",
1100 PyInt_FromLong(MAP_ANON
) );
1103 PyDict_SetItemString (dict
, "PAGESIZE",
1104 PyInt_FromLong( (long)my_getpagesize() ) );
1106 PyDict_SetItemString (dict
, "ACCESS_READ",
1107 PyInt_FromLong(ACCESS_READ
));
1108 PyDict_SetItemString (dict
, "ACCESS_WRITE",
1109 PyInt_FromLong(ACCESS_WRITE
));
1110 PyDict_SetItemString (dict
, "ACCESS_COPY",
1111 PyInt_FromLong(ACCESS_COPY
));