summaryrefslogtreecommitdiffstats
path: root/Modules/mmapmodule.c
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-11-13 23:11:19 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-11-13 23:11:19 (GMT)
commit5ebfd36afa9093099ab23e4d1256274ae7ee6978 (patch)
treeed954f677f6427ad84bead3dc212b8746948f9a8 /Modules/mmapmodule.c
parentafeb2a4d8914848d8761472c93b3e9cbff57b275 (diff)
downloadcpython-5ebfd36afa9093099ab23e4d1256274ae7ee6978.zip
cpython-5ebfd36afa9093099ab23e4d1256274ae7ee6978.tar.gz
cpython-5ebfd36afa9093099ab23e4d1256274ae7ee6978.tar.bz2
CVS patch #477161: New "access" keyword for mmap, from Jay T Miller.
This gives mmap() on Windows the ability to create read-only, write- through and copy-on-write mmaps. A new keyword argument is introduced because the mmap() signatures diverged between Windows and Unix, so while they (now) both support this functionality, there wasn't a way to spell it in a common way without introducing a new spelling gimmick. The old spellings are still accepted, so there isn't a backward- compatibility issue here.
Diffstat (limited to 'Modules/mmapmodule.c')
-rw-r--r--Modules/mmapmodule.c235
1 files changed, 166 insertions, 69 deletions
diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c
index 8d57e90..a4ec2d0 100644
--- a/Modules/mmapmodule.c
+++ b/Modules/mmapmodule.c
@@ -29,9 +29,9 @@
static int
my_getpagesize(void)
{
- SYSTEM_INFO si;
- GetSystemInfo(&si);
- return si.dwPageSize;
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ return si.dwPageSize;
}
#endif
@@ -49,7 +49,7 @@ my_getpagesize(void)
static int
my_getpagesize(void)
{
- return sysconf(_SC_PAGESIZE);
+ return sysconf(_SC_PAGESIZE);
}
#else
#define my_getpagesize getpagesize
@@ -62,6 +62,14 @@ my_getpagesize(void)
static PyObject *mmap_module_error;
+typedef enum
+{
+ ACCESS_DEFAULT,
+ ACCESS_READ,
+ ACCESS_WRITE,
+ ACCESS_COPY
+} access_mode;
+
typedef struct {
PyObject_HEAD
char * data;
@@ -77,8 +85,11 @@ typedef struct {
#ifdef UNIX
int fd;
#endif
+
+ access_mode access;
} mmap_object;
+
static void
mmap_object_dealloc(mmap_object *m_obj)
{
@@ -178,7 +189,7 @@ mmap_read_byte_method(mmap_object *self,
static PyObject *
mmap_read_line_method(mmap_object *self,
- PyObject *args)
+ PyObject *args)
{
char *start = self->data+self->pos;
char *eof = self->data+self->size;
@@ -236,11 +247,11 @@ mmap_find_method(mmap_object *self,
char *e = self->data + self->size;
if (start < 0)
- start += self->size;
+ start += self->size;
if (start < 0)
- start = 0;
+ start = 0;
else if ((size_t)start > self->size)
- start = self->size;
+ start = self->size;
p = self->data + start;
while (p < e) {
@@ -260,6 +271,26 @@ mmap_find_method(mmap_object *self,
}
}
+static int
+is_writeable(mmap_object *self)
+{
+ if (self->access != ACCESS_READ)
+ return 1;
+ PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
+ return 0;
+}
+
+static int
+is_resizeable(mmap_object *self)
+{
+ if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
+ return 1;
+ PyErr_Format(PyExc_TypeError,
+ "mmap can't resize a readonly or copy-on-write memory map.");
+ return 0;
+}
+
+
static PyObject *
mmap_write_method(mmap_object *self,
PyObject *args)
@@ -271,6 +302,9 @@ mmap_write_method(mmap_object *self,
if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
return(NULL);
+ if (!is_writeable(self))
+ return NULL;
+
if ((self->pos + length) > self->size) {
PyErr_SetString (PyExc_ValueError, "data out of range");
return NULL;
@@ -291,12 +325,14 @@ mmap_write_byte_method(mmap_object *self,
if (!PyArg_ParseTuple (args, "c:write_byte", &value))
return(NULL);
+ if (!is_writeable(self))
+ return NULL;
*(self->data+self->pos) = value;
self->pos += 1;
Py_INCREF (Py_None);
return (Py_None);
}
-
+
static PyObject *
mmap_size_method(mmap_object *self,
PyObject *args)
@@ -342,7 +378,8 @@ mmap_resize_method(mmap_object *self,
{
unsigned long new_size;
CHECK_VALID(NULL);
- if (!PyArg_ParseTuple (args, "l:resize", &new_size)) {
+ if (!PyArg_ParseTuple (args, "l:resize", &new_size) ||
+ !is_resizeable(self)) {
return NULL;
#ifdef MS_WIN32
} else {
@@ -386,31 +423,31 @@ mmap_resize_method(mmap_object *self,
#ifdef UNIX
#ifndef HAVE_MREMAP
-} else {
- PyErr_SetString(PyExc_SystemError,
- "mmap: resizing not available--no mremap()");
- return NULL;
+ } else {
+ PyErr_SetString(PyExc_SystemError,
+ "mmap: resizing not available--no mremap()");
+ return NULL;
#else
-} else {
- void *newmap;
+ } else {
+ void *newmap;
#ifdef MREMAP_MAYMOVE
- newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
+ newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
#else
- newmap = mremap(self->data, self->size, new_size, 0);
+ newmap = mremap(self->data, self->size, new_size, 0);
#endif
- if (newmap == (void *)-1)
- {
- PyErr_SetFromErrno(mmap_module_error);
- return NULL;
- }
- self->data = newmap;
- self->size = new_size;
- Py_INCREF(Py_None);
- return Py_None;
+ if (newmap == (void *)-1)
+ {
+ PyErr_SetFromErrno(mmap_module_error);
+ return NULL;
+ }
+ self->data = newmap;
+ self->size = new_size;
+ Py_INCREF(Py_None);
+ return Py_None;
#endif /* HAVE_MREMAP */
#endif /* UNIX */
-}
+ }
}
static PyObject *
@@ -491,7 +528,7 @@ mmap_seek_method(mmap_object *self, PyObject *args)
return (Py_None);
}
-onoutofrange:
+ onoutofrange:
PyErr_SetString (PyExc_ValueError, "seek out of range");
return NULL;
}
@@ -501,7 +538,8 @@ mmap_move_method(mmap_object *self, PyObject *args)
{
unsigned long dest, src, count;
CHECK_VALID(NULL);
- if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count)) {
+ if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count) ||
+ !is_writeable(self)) {
return NULL;
} else {
/* bounds check the values */
@@ -561,6 +599,8 @@ mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
"Accessing non-existent mmap segment");
return -1;
}
+ if (!is_writeable(self))
+ return -1;
*ptr = self->data;
return self->size;
}
@@ -665,7 +705,7 @@ mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
if (v == NULL) {
PyErr_SetString(PyExc_TypeError,
- "mmap object doesn't support slice deletion");
+ "mmap object doesn't support slice deletion");
return -1;
}
if (! (PyString_Check(v)) ) {
@@ -678,6 +718,8 @@ mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
"mmap slice assignment is wrong size");
return -1;
}
+ if (!is_writeable(self))
+ return -1;
buf = PyString_AsString(v);
memcpy(self->data + ilow, buf, ihigh-ilow);
return 0;
@@ -695,14 +737,16 @@ mmap_ass_item(mmap_object *self, int i, PyObject *v)
}
if (v == NULL) {
PyErr_SetString(PyExc_TypeError,
- "mmap object doesn't support item deletion");
+ "mmap object doesn't support item deletion");
return -1;
}
if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
PyErr_SetString(PyExc_IndexError,
- "mmap assignment must be single-character string");
+ "mmap assignment must be single-character string");
return -1;
}
+ if (!is_writeable(self))
+ return -1;
buf = PyString_AsString(v);
self->data[i] = buf[0];
return 0;
@@ -792,18 +836,18 @@ _GetMapSize(PyObject *o)
}
else {
PyErr_SetString(PyExc_TypeError,
- "map size must be an integral value");
+ "map size must be an integral value");
return -1;
}
-onnegoverflow:
+ onnegoverflow:
PyErr_SetString(PyExc_OverflowError,
- "memory mapped size must be positive");
+ "memory mapped size must be positive");
return -1;
-onposoverflow:
+ onposoverflow:
PyErr_SetString(PyExc_OverflowError,
- "memory mapped size is too large (limited by C int)");
+ "memory mapped size is too large (limited by C int)");
return -1;
}
@@ -815,16 +859,42 @@ new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
PyObject *map_size_obj = NULL;
int map_size;
int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
- char *keywords[] = {"file", "size", "flags", "prot", NULL};
+ access_mode access = ACCESS_DEFAULT;
+ char *keywords[] = {"fileno", "length",
+ "flags", "prot",
+ "access", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwdict,
- "iO|ii", keywords,
- &fd, &map_size_obj, &flags, &prot)
- )
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii", keywords,
+ &fd, &map_size_obj, &flags, &prot, &access))
return NULL;
map_size = _GetMapSize(map_size_obj);
if (map_size < 0)
return NULL;
+
+ if ((access != ACCESS_DEFAULT) &&
+ ((flags != MAP_SHARED) || ( prot != (PROT_WRITE | PROT_READ))))
+ return PyErr_Format(PyExc_ValueError,
+ "mmap can't specify both access and flags, prot.");
+ switch(access) {
+ case ACCESS_READ:
+ flags = MAP_SHARED;
+ prot = PROT_READ;
+ break;
+ case ACCESS_WRITE:
+ flags = MAP_SHARED;
+ prot = PROT_READ | PROT_WRITE;
+ break;
+ case ACCESS_COPY:
+ flags = MAP_PRIVATE;
+ prot = PROT_READ | PROT_WRITE;
+ break;
+ case ACCESS_DEFAULT:
+ /* use the specified or default values of flags and prot */
+ break;
+ default:
+ return PyErr_Format(PyExc_ValueError,
+ "mmap invalid access parameter.");
+ }
m_obj = PyObject_New (mmap_object, &mmap_object_type);
if (m_obj == NULL) {return NULL;}
@@ -834,37 +904,57 @@ new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
m_obj->data = mmap(NULL, map_size,
prot, flags,
fd, 0);
- if (m_obj->data == (char *)-1)
- {
+ if (m_obj->data == (char *)-1) {
Py_DECREF(m_obj);
PyErr_SetFromErrno(mmap_module_error);
return NULL;
}
+ m_obj->access = access;
return (PyObject *)m_obj;
}
#endif /* UNIX */
#ifdef MS_WIN32
static PyObject *
-new_mmap_object(PyObject *self, PyObject *args)
+new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
{
mmap_object *m_obj;
PyObject *map_size_obj = NULL;
int map_size;
char *tagname = "";
-
DWORD dwErr = 0;
int fileno;
HANDLE fh = 0;
-
- if (!PyArg_ParseTuple(args,
- "iO|z",
- &fileno,
- &map_size_obj,
- &tagname)
- )
+ access_mode access = ACCESS_DEFAULT;
+ DWORD flProtect, dwDesiredAccess;
+ char *keywords[] = { "fileno", "length",
+ "tagname",
+ "access", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|zi", keywords,
+ &fileno, &map_size_obj,
+ &tagname, &access)) {
return NULL;
-
+ }
+
+ switch(access) {
+ case ACCESS_READ:
+ flProtect = PAGE_READONLY;
+ dwDesiredAccess = FILE_MAP_READ;
+ break;
+ case ACCESS_DEFAULT: case ACCESS_WRITE:
+ flProtect = PAGE_READWRITE;
+ dwDesiredAccess = FILE_MAP_WRITE;
+ break;
+ case ACCESS_COPY:
+ flProtect = PAGE_WRITECOPY;
+ dwDesiredAccess = FILE_MAP_COPY;
+ break;
+ default:
+ return PyErr_Format(PyExc_ValueError,
+ "mmap invalid access parameter.");
+ }
+
map_size = _GetMapSize(map_size_obj);
if (map_size < 0)
return NULL;
@@ -873,8 +963,8 @@ new_mmap_object(PyObject *self, PyObject *args)
if (fileno != 0) {
fh = (HANDLE)_get_osfhandle(fileno);
if (fh==(HANDLE)-1) {
- PyErr_SetFromErrno(mmap_module_error);
- return NULL;
+ PyErr_SetFromErrno(mmap_module_error);
+ return NULL;
}
/* Win9x appears to need us seeked to zero */
fseek(&_iob[fileno], 0, SEEK_SET);
@@ -894,13 +984,13 @@ new_mmap_object(PyObject *self, PyObject *args)
/* It is necessary to duplicate the handle, so the
Python code can close it on us */
if (!DuplicateHandle(
- GetCurrentProcess(), /* source process handle */
- fh, /* handle to be duplicated */
- GetCurrentProcess(), /* target proc handle */
- (LPHANDLE)&m_obj->file_handle, /* result */
- 0, /* access - ignored due to options value */
- FALSE, /* inherited by child processes? */
- DUPLICATE_SAME_ACCESS)) { /* options */
+ GetCurrentProcess(), /* source process handle */
+ fh, /* handle to be duplicated */
+ GetCurrentProcess(), /* target proc handle */
+ (LPHANDLE)&m_obj->file_handle, /* result */
+ 0, /* access - ignored due to options value */
+ FALSE, /* inherited by child processes? */
+ DUPLICATE_SAME_ACCESS)) { /* options */
dwErr = GetLastError();
Py_DECREF(m_obj);
PyErr_SetFromWindowsErr(dwErr);
@@ -932,22 +1022,23 @@ new_mmap_object(PyObject *self, PyObject *args)
else
m_obj->tagname = NULL;
+ m_obj->access = access;
m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
NULL,
- PAGE_READWRITE,
+ flProtect,
0,
m_obj->size,
m_obj->tagname);
if (m_obj->map_handle != NULL) {
m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
- FILE_MAP_WRITE,
+ dwDesiredAccess,
0,
0,
0);
if (m_obj->data != NULL) {
return ((PyObject *) m_obj);
} else {
- dwErr = GetLastError();
+ dwErr = GetLastError();
}
} else {
dwErr = GetLastError();
@@ -966,7 +1057,7 @@ static struct PyMethodDef mmap_functions[] = {
};
DL_EXPORT(void)
-initmmap(void)
+ initmmap(void)
{
PyObject *dict, *module;
@@ -1011,5 +1102,11 @@ initmmap(void)
PyDict_SetItemString (dict, "PAGESIZE",
PyInt_FromLong( (long)my_getpagesize() ) );
-}
+ PyDict_SetItemString (dict, "ACCESS_READ",
+ PyInt_FromLong(ACCESS_READ));
+ PyDict_SetItemString (dict, "ACCESS_WRITE",
+ PyInt_FromLong(ACCESS_WRITE));
+ PyDict_SetItemString (dict, "ACCESS_COPY",
+ PyInt_FromLong(ACCESS_COPY));
+}