diff options
Diffstat (limited to 'contrib/tools/python3/src/Modules/mmapmodule.c')
| -rw-r--r-- | contrib/tools/python3/src/Modules/mmapmodule.c | 2850 |
1 files changed, 1425 insertions, 1425 deletions
diff --git a/contrib/tools/python3/src/Modules/mmapmodule.c b/contrib/tools/python3/src/Modules/mmapmodule.c index a3e22d0a511..042aae6aa95 100644 --- a/contrib/tools/python3/src/Modules/mmapmodule.c +++ b/contrib/tools/python3/src/Modules/mmapmodule.c @@ -1,166 +1,166 @@ -/* - / Author: Sam Rushing <[email protected]> - / Hacked for Unix by AMK - / $Id$ - - / Modified to support mmap with offset - to map a 'window' of a file - / Author: Yotam Medini [email protected] - / - / mmapmodule.cpp -- map a view of a file into memory - / - / todo: need permission flags, perhaps a 'chsize' analog - / not all functions check range yet!!! - / - / - / This version of mmapmodule.c has been changed significantly - / from the original mmapfile.c on which it was based. - / The original version of mmapfile is maintained by Sam at - / ftp://squirl.nightmare.com/pub/python/python-ext. -*/ - -#define PY_SSIZE_T_CLEAN -#include <Python.h> +/* + / Author: Sam Rushing <[email protected]> + / Hacked for Unix by AMK + / $Id$ + + / Modified to support mmap with offset - to map a 'window' of a file + / Author: Yotam Medini [email protected] + / + / mmapmodule.cpp -- map a view of a file into memory + / + / todo: need permission flags, perhaps a 'chsize' analog + / not all functions check range yet!!! + / + / + / This version of mmapmodule.c has been changed significantly + / from the original mmapfile.c on which it was based. + / The original version of mmapfile is maintained by Sam at + / ftp://squirl.nightmare.com/pub/python/python-ext. +*/ + +#define PY_SSIZE_T_CLEAN +#include <Python.h> #include <stddef.h> // offsetof() - -#ifndef MS_WINDOWS -#define UNIX -# ifdef HAVE_FCNTL_H -# include <fcntl.h> -# endif /* HAVE_FCNTL_H */ -#endif - -#ifdef MS_WINDOWS -#include <windows.h> -static int -my_getpagesize(void) -{ - SYSTEM_INFO si; - GetSystemInfo(&si); - return si.dwPageSize; -} - -static int -my_getallocationgranularity (void) -{ - - SYSTEM_INFO si; - GetSystemInfo(&si); - return si.dwAllocationGranularity; -} - -#endif - -#ifdef UNIX -#include <sys/mman.h> -#include <sys/stat.h> - -#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) -static int -my_getpagesize(void) -{ - return sysconf(_SC_PAGESIZE); -} - -#define my_getallocationgranularity my_getpagesize -#else -#define my_getpagesize getpagesize -#endif - -#endif /* UNIX */ - -#include <string.h> - -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif /* HAVE_SYS_TYPES_H */ - -/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */ -#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) -# define MAP_ANONYMOUS MAP_ANON -#endif - -typedef enum -{ - ACCESS_DEFAULT, - ACCESS_READ, - ACCESS_WRITE, - ACCESS_COPY -} access_mode; - -typedef struct { - PyObject_HEAD - char * data; - Py_ssize_t size; - Py_ssize_t pos; /* relative to offset */ -#ifdef MS_WINDOWS - long long offset; -#else - off_t offset; -#endif + +#ifndef MS_WINDOWS +#define UNIX +# ifdef HAVE_FCNTL_H +# include <fcntl.h> +# endif /* HAVE_FCNTL_H */ +#endif + +#ifdef MS_WINDOWS +#include <windows.h> +static int +my_getpagesize(void) +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwPageSize; +} + +static int +my_getallocationgranularity (void) +{ + + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwAllocationGranularity; +} + +#endif + +#ifdef UNIX +#include <sys/mman.h> +#include <sys/stat.h> + +#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) +static int +my_getpagesize(void) +{ + return sysconf(_SC_PAGESIZE); +} + +#define my_getallocationgranularity my_getpagesize +#else +#define my_getpagesize getpagesize +#endif + +#endif /* UNIX */ + +#include <string.h> + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif /* HAVE_SYS_TYPES_H */ + +/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */ +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +# define MAP_ANONYMOUS MAP_ANON +#endif + +typedef enum +{ + ACCESS_DEFAULT, + ACCESS_READ, + ACCESS_WRITE, + ACCESS_COPY +} access_mode; + +typedef struct { + PyObject_HEAD + char * data; + Py_ssize_t size; + Py_ssize_t pos; /* relative to offset */ +#ifdef MS_WINDOWS + long long offset; +#else + off_t offset; +#endif Py_ssize_t exports; - -#ifdef MS_WINDOWS - HANDLE map_handle; - HANDLE file_handle; - char * tagname; -#endif - -#ifdef UNIX - int fd; -#endif - - PyObject *weakreflist; - access_mode access; -} mmap_object; - - -static void -mmap_object_dealloc(mmap_object *m_obj) -{ -#ifdef MS_WINDOWS + +#ifdef MS_WINDOWS + HANDLE map_handle; + HANDLE file_handle; + char * tagname; +#endif + +#ifdef UNIX + int fd; +#endif + + PyObject *weakreflist; + access_mode access; +} mmap_object; + + +static void +mmap_object_dealloc(mmap_object *m_obj) +{ +#ifdef MS_WINDOWS Py_BEGIN_ALLOW_THREADS - if (m_obj->data != NULL) - UnmapViewOfFile (m_obj->data); - if (m_obj->map_handle != NULL) - CloseHandle (m_obj->map_handle); - if (m_obj->file_handle != INVALID_HANDLE_VALUE) - CloseHandle (m_obj->file_handle); + if (m_obj->data != NULL) + UnmapViewOfFile (m_obj->data); + if (m_obj->map_handle != NULL) + CloseHandle (m_obj->map_handle); + if (m_obj->file_handle != INVALID_HANDLE_VALUE) + CloseHandle (m_obj->file_handle); Py_END_ALLOW_THREADS - if (m_obj->tagname) - PyMem_Free(m_obj->tagname); -#endif /* MS_WINDOWS */ - -#ifdef UNIX + if (m_obj->tagname) + PyMem_Free(m_obj->tagname); +#endif /* MS_WINDOWS */ + +#ifdef UNIX Py_BEGIN_ALLOW_THREADS - if (m_obj->fd >= 0) - (void) close(m_obj->fd); - if (m_obj->data!=NULL) { - munmap(m_obj->data, m_obj->size); - } + if (m_obj->fd >= 0) + (void) close(m_obj->fd); + if (m_obj->data!=NULL) { + munmap(m_obj->data, m_obj->size); + } Py_END_ALLOW_THREADS -#endif /* UNIX */ - - if (m_obj->weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *) m_obj); - Py_TYPE(m_obj)->tp_free((PyObject*)m_obj); -} - -static PyObject * -mmap_close_method(mmap_object *self, PyObject *unused) -{ - if (self->exports > 0) { - PyErr_SetString(PyExc_BufferError, "cannot close "\ - "exported pointers exist"); - return NULL; - } -#ifdef MS_WINDOWS - /* For each resource we maintain, we need to check - the value is valid, and if so, free the resource - and set the member value to an invalid value so - the dealloc does not attempt to resource clearing - again. - TODO - should we check for errors in the close operations??? - */ +#endif /* UNIX */ + + if (m_obj->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) m_obj); + Py_TYPE(m_obj)->tp_free((PyObject*)m_obj); +} + +static PyObject * +mmap_close_method(mmap_object *self, PyObject *unused) +{ + if (self->exports > 0) { + PyErr_SetString(PyExc_BufferError, "cannot close "\ + "exported pointers exist"); + return NULL; + } +#ifdef MS_WINDOWS + /* For each resource we maintain, we need to check + the value is valid, and if so, free the resource + and set the member value to an invalid value so + the dealloc does not attempt to resource clearing + again. + TODO - should we check for errors in the close operations??? + */ HANDLE map_handle = self->map_handle; HANDLE file_handle = self->file_handle; char *data = self->data; @@ -170,537 +170,537 @@ mmap_close_method(mmap_object *self, PyObject *unused) Py_BEGIN_ALLOW_THREADS if (data != NULL) { UnmapViewOfFile(data); - } + } if (map_handle != NULL) { CloseHandle(map_handle); - } + } if (file_handle != INVALID_HANDLE_VALUE) { CloseHandle(file_handle); - } + } Py_END_ALLOW_THREADS -#endif /* MS_WINDOWS */ - -#ifdef UNIX +#endif /* MS_WINDOWS */ + +#ifdef UNIX int fd = self->fd; char *data = self->data; - self->fd = -1; + self->fd = -1; self->data = NULL; Py_BEGIN_ALLOW_THREADS if (0 <= fd) (void) close(fd); if (data != NULL) { munmap(data, self->size); - } + } Py_END_ALLOW_THREADS -#endif - - Py_RETURN_NONE; -} - -#ifdef MS_WINDOWS -#define CHECK_VALID(err) \ -do { \ - if (self->map_handle == NULL) { \ - PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \ - return err; \ - } \ -} while (0) -#endif /* MS_WINDOWS */ - -#ifdef UNIX -#define CHECK_VALID(err) \ -do { \ - if (self->data == NULL) { \ - PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \ - return err; \ - } \ -} while (0) -#endif /* UNIX */ - -static PyObject * -mmap_read_byte_method(mmap_object *self, - PyObject *unused) -{ - CHECK_VALID(NULL); - if (self->pos >= self->size) { - PyErr_SetString(PyExc_ValueError, "read byte out of range"); - return NULL; - } - return PyLong_FromLong((unsigned char)self->data[self->pos++]); -} - -static PyObject * -mmap_read_line_method(mmap_object *self, - PyObject *unused) -{ - Py_ssize_t remaining; - char *start, *eol; - PyObject *result; - - CHECK_VALID(NULL); - - remaining = (self->pos < self->size) ? self->size - self->pos : 0; - if (!remaining) - return PyBytes_FromString(""); - start = self->data + self->pos; - eol = memchr(start, '\n', remaining); - if (!eol) - eol = self->data + self->size; - else - ++eol; /* advance past newline */ - result = PyBytes_FromStringAndSize(start, (eol - start)); - self->pos += (eol - start); - return result; -} - -static PyObject * -mmap_read_method(mmap_object *self, - PyObject *args) -{ - Py_ssize_t num_bytes = PY_SSIZE_T_MAX, remaining; - PyObject *result; - - CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "|O&:read", _Py_convert_optional_to_ssize_t, &num_bytes)) - return(NULL); - - /* silently 'adjust' out-of-range requests */ - remaining = (self->pos < self->size) ? self->size - self->pos : 0; - if (num_bytes < 0 || num_bytes > remaining) - num_bytes = remaining; - result = PyBytes_FromStringAndSize(&self->data[self->pos], num_bytes); - self->pos += num_bytes; - return result; -} - -static PyObject * -mmap_gfind(mmap_object *self, - PyObject *args, - int reverse) -{ - Py_ssize_t start = self->pos; - Py_ssize_t end = self->size; - Py_buffer view; - - CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, reverse ? "y*|nn:rfind" : "y*|nn:find", - &view, &start, &end)) { - return NULL; - } else { - const char *p, *start_p, *end_p; - int sign = reverse ? -1 : 1; - const char *needle = view.buf; - Py_ssize_t len = view.len; - - if (start < 0) - start += self->size; - if (start < 0) - start = 0; - else if (start > self->size) - start = self->size; - - if (end < 0) - end += self->size; - if (end < 0) - end = 0; - else if (end > self->size) - end = self->size; - - start_p = self->data + start; - end_p = self->data + end; - - for (p = (reverse ? end_p - len : start_p); - (p >= start_p) && (p + len <= end_p); p += sign) { - Py_ssize_t i; - for (i = 0; i < len && needle[i] == p[i]; ++i) - /* nothing */; - if (i == len) { - PyBuffer_Release(&view); - return PyLong_FromSsize_t(p - self->data); - } - } - PyBuffer_Release(&view); - return PyLong_FromLong(-1); - } -} - -static PyObject * -mmap_find_method(mmap_object *self, - PyObject *args) -{ - return mmap_gfind(self, args, 0); -} - -static PyObject * -mmap_rfind_method(mmap_object *self, - PyObject *args) -{ - return mmap_gfind(self, args, 1); -} - -static int -is_writable(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->exports > 0) { - PyErr_SetString(PyExc_BufferError, - "mmap can't resize with extant buffers exported."); - return 0; - } - 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) -{ - Py_buffer data; - - CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "y*:write", &data)) - return(NULL); - - if (!is_writable(self)) { - PyBuffer_Release(&data); - return NULL; - } - - if (self->pos > self->size || self->size - self->pos < data.len) { - PyBuffer_Release(&data); - PyErr_SetString(PyExc_ValueError, "data out of range"); - return NULL; - } - - memcpy(&self->data[self->pos], data.buf, data.len); - self->pos += data.len; - PyBuffer_Release(&data); - return PyLong_FromSsize_t(data.len); -} - -static PyObject * -mmap_write_byte_method(mmap_object *self, - PyObject *args) -{ - char value; - - CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "b:write_byte", &value)) - return(NULL); - - if (!is_writable(self)) - return NULL; - - if (self->pos < self->size) { - self->data[self->pos++] = value; - Py_RETURN_NONE; - } - else { - PyErr_SetString(PyExc_ValueError, "write byte out of range"); - return NULL; - } -} - -static PyObject * -mmap_size_method(mmap_object *self, - PyObject *unused) -{ - CHECK_VALID(NULL); - -#ifdef MS_WINDOWS - if (self->file_handle != INVALID_HANDLE_VALUE) { - DWORD low,high; - long long size; - low = GetFileSize(self->file_handle, &high); - if (low == INVALID_FILE_SIZE) { - /* It might be that the function appears to have failed, - when indeed its size equals INVALID_FILE_SIZE */ - DWORD error = GetLastError(); - if (error != NO_ERROR) - return PyErr_SetFromWindowsErr(error); - } - if (!high && low < LONG_MAX) - return PyLong_FromLong((long)low); - size = (((long long)high)<<32) + low; - return PyLong_FromLongLong(size); - } else { - return PyLong_FromSsize_t(self->size); - } -#endif /* MS_WINDOWS */ - -#ifdef UNIX - { - struct _Py_stat_struct status; - if (_Py_fstat(self->fd, &status) == -1) - return NULL; -#ifdef HAVE_LARGEFILE_SUPPORT - return PyLong_FromLongLong(status.st_size); -#else - return PyLong_FromLong(status.st_size); -#endif - } -#endif /* UNIX */ -} - -/* This assumes that you want the entire file mapped, - / and when recreating the map will make the new file - / have the new size - / - / Is this really necessary? This could easily be done - / from python by just closing and re-opening with the - / new size? - */ - -static PyObject * -mmap_resize_method(mmap_object *self, - PyObject *args) -{ - Py_ssize_t new_size; - CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "n:resize", &new_size) || - !is_resizeable(self)) { - return NULL; - } - if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) { - PyErr_SetString(PyExc_ValueError, "new size out of range"); - return NULL; - } - - { -#ifdef MS_WINDOWS - DWORD dwErrCode = 0; - DWORD off_hi, off_lo, newSizeLow, newSizeHigh; - /* First, unmap the file view */ - UnmapViewOfFile(self->data); - self->data = NULL; - /* Close the mapping object */ - CloseHandle(self->map_handle); - self->map_handle = NULL; - /* Move to the desired EOF position */ - newSizeHigh = (DWORD)((self->offset + new_size) >> 32); - newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF); - off_hi = (DWORD)(self->offset >> 32); - off_lo = (DWORD)(self->offset & 0xFFFFFFFF); - SetFilePointer(self->file_handle, - newSizeLow, &newSizeHigh, FILE_BEGIN); - /* Change the size of the file */ - SetEndOfFile(self->file_handle); - /* Create another mapping object and remap the file view */ - self->map_handle = CreateFileMapping( - self->file_handle, - NULL, - PAGE_READWRITE, - 0, - 0, - self->tagname); - if (self->map_handle != NULL) { - self->data = (char *) MapViewOfFile(self->map_handle, - FILE_MAP_WRITE, - off_hi, - off_lo, - new_size); - if (self->data != NULL) { - self->size = new_size; - Py_RETURN_NONE; - } else { - dwErrCode = GetLastError(); - CloseHandle(self->map_handle); - self->map_handle = NULL; - } - } else { - dwErrCode = GetLastError(); - } - PyErr_SetFromWindowsErr(dwErrCode); - return NULL; -#endif /* MS_WINDOWS */ - -#ifdef UNIX -#ifndef HAVE_MREMAP - PyErr_SetString(PyExc_SystemError, - "mmap: resizing not available--no mremap()"); - return NULL; -#else - void *newmap; - - if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - -#ifdef MREMAP_MAYMOVE - newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE); -#else -#if defined(__NetBSD__) - newmap = mremap(self->data, self->size, self->data, new_size, 0); -#else - newmap = mremap(self->data, self->size, new_size, 0); -#endif /* __NetBSD__ */ -#endif - if (newmap == (void *)-1) - { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - self->data = newmap; - self->size = new_size; - Py_RETURN_NONE; -#endif /* HAVE_MREMAP */ -#endif /* UNIX */ - } -} - -static PyObject * -mmap_tell_method(mmap_object *self, PyObject *unused) -{ - CHECK_VALID(NULL); - return PyLong_FromSize_t(self->pos); -} - -static PyObject * -mmap_flush_method(mmap_object *self, PyObject *args) -{ - Py_ssize_t offset = 0; - Py_ssize_t size = self->size; - CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size)) - return NULL; - if (size < 0 || offset < 0 || self->size - offset < size) { - PyErr_SetString(PyExc_ValueError, "flush values out of range"); - return NULL; - } - - if (self->access == ACCESS_READ || self->access == ACCESS_COPY) +#endif + + Py_RETURN_NONE; +} + +#ifdef MS_WINDOWS +#define CHECK_VALID(err) \ +do { \ + if (self->map_handle == NULL) { \ + PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \ + return err; \ + } \ +} while (0) +#endif /* MS_WINDOWS */ + +#ifdef UNIX +#define CHECK_VALID(err) \ +do { \ + if (self->data == NULL) { \ + PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \ + return err; \ + } \ +} while (0) +#endif /* UNIX */ + +static PyObject * +mmap_read_byte_method(mmap_object *self, + PyObject *unused) +{ + CHECK_VALID(NULL); + if (self->pos >= self->size) { + PyErr_SetString(PyExc_ValueError, "read byte out of range"); + return NULL; + } + return PyLong_FromLong((unsigned char)self->data[self->pos++]); +} + +static PyObject * +mmap_read_line_method(mmap_object *self, + PyObject *unused) +{ + Py_ssize_t remaining; + char *start, *eol; + PyObject *result; + + CHECK_VALID(NULL); + + remaining = (self->pos < self->size) ? self->size - self->pos : 0; + if (!remaining) + return PyBytes_FromString(""); + start = self->data + self->pos; + eol = memchr(start, '\n', remaining); + if (!eol) + eol = self->data + self->size; + else + ++eol; /* advance past newline */ + result = PyBytes_FromStringAndSize(start, (eol - start)); + self->pos += (eol - start); + return result; +} + +static PyObject * +mmap_read_method(mmap_object *self, + PyObject *args) +{ + Py_ssize_t num_bytes = PY_SSIZE_T_MAX, remaining; + PyObject *result; + + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, "|O&:read", _Py_convert_optional_to_ssize_t, &num_bytes)) + return(NULL); + + /* silently 'adjust' out-of-range requests */ + remaining = (self->pos < self->size) ? self->size - self->pos : 0; + if (num_bytes < 0 || num_bytes > remaining) + num_bytes = remaining; + result = PyBytes_FromStringAndSize(&self->data[self->pos], num_bytes); + self->pos += num_bytes; + return result; +} + +static PyObject * +mmap_gfind(mmap_object *self, + PyObject *args, + int reverse) +{ + Py_ssize_t start = self->pos; + Py_ssize_t end = self->size; + Py_buffer view; + + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, reverse ? "y*|nn:rfind" : "y*|nn:find", + &view, &start, &end)) { + return NULL; + } else { + const char *p, *start_p, *end_p; + int sign = reverse ? -1 : 1; + const char *needle = view.buf; + Py_ssize_t len = view.len; + + if (start < 0) + start += self->size; + if (start < 0) + start = 0; + else if (start > self->size) + start = self->size; + + if (end < 0) + end += self->size; + if (end < 0) + end = 0; + else if (end > self->size) + end = self->size; + + start_p = self->data + start; + end_p = self->data + end; + + for (p = (reverse ? end_p - len : start_p); + (p >= start_p) && (p + len <= end_p); p += sign) { + Py_ssize_t i; + for (i = 0; i < len && needle[i] == p[i]; ++i) + /* nothing */; + if (i == len) { + PyBuffer_Release(&view); + return PyLong_FromSsize_t(p - self->data); + } + } + PyBuffer_Release(&view); + return PyLong_FromLong(-1); + } +} + +static PyObject * +mmap_find_method(mmap_object *self, + PyObject *args) +{ + return mmap_gfind(self, args, 0); +} + +static PyObject * +mmap_rfind_method(mmap_object *self, + PyObject *args) +{ + return mmap_gfind(self, args, 1); +} + +static int +is_writable(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->exports > 0) { + PyErr_SetString(PyExc_BufferError, + "mmap can't resize with extant buffers exported."); + return 0; + } + 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) +{ + Py_buffer data; + + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, "y*:write", &data)) + return(NULL); + + if (!is_writable(self)) { + PyBuffer_Release(&data); + return NULL; + } + + if (self->pos > self->size || self->size - self->pos < data.len) { + PyBuffer_Release(&data); + PyErr_SetString(PyExc_ValueError, "data out of range"); + return NULL; + } + + memcpy(&self->data[self->pos], data.buf, data.len); + self->pos += data.len; + PyBuffer_Release(&data); + return PyLong_FromSsize_t(data.len); +} + +static PyObject * +mmap_write_byte_method(mmap_object *self, + PyObject *args) +{ + char value; + + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, "b:write_byte", &value)) + return(NULL); + + if (!is_writable(self)) + return NULL; + + if (self->pos < self->size) { + self->data[self->pos++] = value; + Py_RETURN_NONE; + } + else { + PyErr_SetString(PyExc_ValueError, "write byte out of range"); + return NULL; + } +} + +static PyObject * +mmap_size_method(mmap_object *self, + PyObject *unused) +{ + CHECK_VALID(NULL); + +#ifdef MS_WINDOWS + if (self->file_handle != INVALID_HANDLE_VALUE) { + DWORD low,high; + long long size; + low = GetFileSize(self->file_handle, &high); + if (low == INVALID_FILE_SIZE) { + /* It might be that the function appears to have failed, + when indeed its size equals INVALID_FILE_SIZE */ + DWORD error = GetLastError(); + if (error != NO_ERROR) + return PyErr_SetFromWindowsErr(error); + } + if (!high && low < LONG_MAX) + return PyLong_FromLong((long)low); + size = (((long long)high)<<32) + low; + return PyLong_FromLongLong(size); + } else { + return PyLong_FromSsize_t(self->size); + } +#endif /* MS_WINDOWS */ + +#ifdef UNIX + { + struct _Py_stat_struct status; + if (_Py_fstat(self->fd, &status) == -1) + return NULL; +#ifdef HAVE_LARGEFILE_SUPPORT + return PyLong_FromLongLong(status.st_size); +#else + return PyLong_FromLong(status.st_size); +#endif + } +#endif /* UNIX */ +} + +/* This assumes that you want the entire file mapped, + / and when recreating the map will make the new file + / have the new size + / + / Is this really necessary? This could easily be done + / from python by just closing and re-opening with the + / new size? + */ + +static PyObject * +mmap_resize_method(mmap_object *self, + PyObject *args) +{ + Py_ssize_t new_size; + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, "n:resize", &new_size) || + !is_resizeable(self)) { + return NULL; + } + if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) { + PyErr_SetString(PyExc_ValueError, "new size out of range"); + return NULL; + } + + { +#ifdef MS_WINDOWS + DWORD dwErrCode = 0; + DWORD off_hi, off_lo, newSizeLow, newSizeHigh; + /* First, unmap the file view */ + UnmapViewOfFile(self->data); + self->data = NULL; + /* Close the mapping object */ + CloseHandle(self->map_handle); + self->map_handle = NULL; + /* Move to the desired EOF position */ + newSizeHigh = (DWORD)((self->offset + new_size) >> 32); + newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF); + off_hi = (DWORD)(self->offset >> 32); + off_lo = (DWORD)(self->offset & 0xFFFFFFFF); + SetFilePointer(self->file_handle, + newSizeLow, &newSizeHigh, FILE_BEGIN); + /* Change the size of the file */ + SetEndOfFile(self->file_handle); + /* Create another mapping object and remap the file view */ + self->map_handle = CreateFileMapping( + self->file_handle, + NULL, + PAGE_READWRITE, + 0, + 0, + self->tagname); + if (self->map_handle != NULL) { + self->data = (char *) MapViewOfFile(self->map_handle, + FILE_MAP_WRITE, + off_hi, + off_lo, + new_size); + if (self->data != NULL) { + self->size = new_size; + Py_RETURN_NONE; + } else { + dwErrCode = GetLastError(); + CloseHandle(self->map_handle); + self->map_handle = NULL; + } + } else { + dwErrCode = GetLastError(); + } + PyErr_SetFromWindowsErr(dwErrCode); + return NULL; +#endif /* MS_WINDOWS */ + +#ifdef UNIX +#ifndef HAVE_MREMAP + PyErr_SetString(PyExc_SystemError, + "mmap: resizing not available--no mremap()"); + return NULL; +#else + void *newmap; + + if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + +#ifdef MREMAP_MAYMOVE + newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE); +#else +#if defined(__NetBSD__) + newmap = mremap(self->data, self->size, self->data, new_size, 0); +#else + newmap = mremap(self->data, self->size, new_size, 0); +#endif /* __NetBSD__ */ +#endif + if (newmap == (void *)-1) + { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + self->data = newmap; + self->size = new_size; + Py_RETURN_NONE; +#endif /* HAVE_MREMAP */ +#endif /* UNIX */ + } +} + +static PyObject * +mmap_tell_method(mmap_object *self, PyObject *unused) +{ + CHECK_VALID(NULL); + return PyLong_FromSize_t(self->pos); +} + +static PyObject * +mmap_flush_method(mmap_object *self, PyObject *args) +{ + Py_ssize_t offset = 0; + Py_ssize_t size = self->size; + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size)) + return NULL; + if (size < 0 || offset < 0 || self->size - offset < size) { + PyErr_SetString(PyExc_ValueError, "flush values out of range"); + return NULL; + } + + if (self->access == ACCESS_READ || self->access == ACCESS_COPY) Py_RETURN_NONE; - -#ifdef MS_WINDOWS + +#ifdef MS_WINDOWS if (!FlushViewOfFile(self->data+offset, size)) { PyErr_SetFromWindowsErr(GetLastError()); return NULL; } Py_RETURN_NONE; -#elif defined(UNIX) - /* XXX flags for msync? */ - if (-1 == msync(self->data + offset, size, MS_SYNC)) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } +#elif defined(UNIX) + /* XXX flags for msync? */ + if (-1 == msync(self->data + offset, size, MS_SYNC)) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } Py_RETURN_NONE; -#else - PyErr_SetString(PyExc_ValueError, "flush not supported on this system"); - return NULL; -#endif -} - -static PyObject * -mmap_seek_method(mmap_object *self, PyObject *args) -{ - Py_ssize_t dist; - int how=0; - CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how)) - return NULL; - else { - Py_ssize_t where; - switch (how) { - case 0: /* relative to start */ - where = dist; - break; - case 1: /* relative to current position */ - if (PY_SSIZE_T_MAX - self->pos < dist) - goto onoutofrange; - where = self->pos + dist; - break; - case 2: /* relative to end */ - if (PY_SSIZE_T_MAX - self->size < dist) - goto onoutofrange; - where = self->size + dist; - break; - default: - PyErr_SetString(PyExc_ValueError, "unknown seek type"); - return NULL; - } - if (where > self->size || where < 0) - goto onoutofrange; - self->pos = where; - Py_RETURN_NONE; - } - - onoutofrange: - PyErr_SetString(PyExc_ValueError, "seek out of range"); - return NULL; -} - -static PyObject * -mmap_move_method(mmap_object *self, PyObject *args) -{ - Py_ssize_t dest, src, cnt; - CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) || - !is_writable(self)) { - return NULL; - } else { - /* bounds check the values */ - if (dest < 0 || src < 0 || cnt < 0) - goto bounds; - if (self->size - dest < cnt || self->size - src < cnt) - goto bounds; - - memmove(&self->data[dest], &self->data[src], cnt); - - Py_RETURN_NONE; - - bounds: - PyErr_SetString(PyExc_ValueError, - "source, destination, or count out of range"); - return NULL; - } -} - -static PyObject * -mmap_closed_get(mmap_object *self, void *Py_UNUSED(ignored)) -{ -#ifdef MS_WINDOWS - return PyBool_FromLong(self->map_handle == NULL ? 1 : 0); -#elif defined(UNIX) - return PyBool_FromLong(self->data == NULL ? 1 : 0); -#endif -} - -static PyObject * -mmap__enter__method(mmap_object *self, PyObject *args) -{ - CHECK_VALID(NULL); - - Py_INCREF(self); - return (PyObject *)self; -} - -static PyObject * -mmap__exit__method(PyObject *self, PyObject *args) -{ - _Py_IDENTIFIER(close); - +#else + PyErr_SetString(PyExc_ValueError, "flush not supported on this system"); + return NULL; +#endif +} + +static PyObject * +mmap_seek_method(mmap_object *self, PyObject *args) +{ + Py_ssize_t dist; + int how=0; + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how)) + return NULL; + else { + Py_ssize_t where; + switch (how) { + case 0: /* relative to start */ + where = dist; + break; + case 1: /* relative to current position */ + if (PY_SSIZE_T_MAX - self->pos < dist) + goto onoutofrange; + where = self->pos + dist; + break; + case 2: /* relative to end */ + if (PY_SSIZE_T_MAX - self->size < dist) + goto onoutofrange; + where = self->size + dist; + break; + default: + PyErr_SetString(PyExc_ValueError, "unknown seek type"); + return NULL; + } + if (where > self->size || where < 0) + goto onoutofrange; + self->pos = where; + Py_RETURN_NONE; + } + + onoutofrange: + PyErr_SetString(PyExc_ValueError, "seek out of range"); + return NULL; +} + +static PyObject * +mmap_move_method(mmap_object *self, PyObject *args) +{ + Py_ssize_t dest, src, cnt; + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) || + !is_writable(self)) { + return NULL; + } else { + /* bounds check the values */ + if (dest < 0 || src < 0 || cnt < 0) + goto bounds; + if (self->size - dest < cnt || self->size - src < cnt) + goto bounds; + + memmove(&self->data[dest], &self->data[src], cnt); + + Py_RETURN_NONE; + + bounds: + PyErr_SetString(PyExc_ValueError, + "source, destination, or count out of range"); + return NULL; + } +} + +static PyObject * +mmap_closed_get(mmap_object *self, void *Py_UNUSED(ignored)) +{ +#ifdef MS_WINDOWS + return PyBool_FromLong(self->map_handle == NULL ? 1 : 0); +#elif defined(UNIX) + return PyBool_FromLong(self->data == NULL ? 1 : 0); +#endif +} + +static PyObject * +mmap__enter__method(mmap_object *self, PyObject *args) +{ + CHECK_VALID(NULL); + + Py_INCREF(self); + return (PyObject *)self; +} + +static PyObject * +mmap__exit__method(PyObject *self, PyObject *args) +{ + _Py_IDENTIFIER(close); + return _PyObject_CallMethodIdNoArgs(self, &PyId_close); -} - +} + static PyObject * mmap__repr__method(PyObject *self) { mmap_object *mobj = (mmap_object *)self; -#ifdef MS_WINDOWS +#ifdef MS_WINDOWS #define _Py_FORMAT_OFFSET "lld" if (mobj->map_handle == NULL) #elif defined(UNIX) @@ -741,18 +741,18 @@ mmap__repr__method(PyObject *self) } #ifdef MS_WINDOWS -static PyObject * -mmap__sizeof__method(mmap_object *self, void *unused) -{ - Py_ssize_t res; - - res = _PyObject_SIZE(Py_TYPE(self)); - if (self->tagname) - res += strlen(self->tagname) + 1; - return PyLong_FromSsize_t(res); -} -#endif - +static PyObject * +mmap__sizeof__method(mmap_object *self, void *unused) +{ + Py_ssize_t res; + + res = _PyObject_SIZE(Py_TYPE(self)); + if (self->tagname) + res += strlen(self->tagname) + 1; + return PyLong_FromSsize_t(res); +} +#endif + #ifdef HAVE_MADVISE static PyObject * mmap_madvise_method(mmap_object *self, PyObject *args) @@ -793,309 +793,309 @@ mmap_madvise_method(mmap_object *self, PyObject *args) } #endif // HAVE_MADVISE -static struct PyMethodDef mmap_object_methods[] = { - {"close", (PyCFunction) mmap_close_method, METH_NOARGS}, - {"find", (PyCFunction) mmap_find_method, METH_VARARGS}, - {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS}, - {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS}, +static struct PyMethodDef mmap_object_methods[] = { + {"close", (PyCFunction) mmap_close_method, METH_NOARGS}, + {"find", (PyCFunction) mmap_find_method, METH_VARARGS}, + {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS}, + {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS}, #ifdef HAVE_MADVISE {"madvise", (PyCFunction) mmap_madvise_method, METH_VARARGS}, #endif - {"move", (PyCFunction) mmap_move_method, METH_VARARGS}, - {"read", (PyCFunction) mmap_read_method, METH_VARARGS}, - {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS}, - {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS}, - {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS}, - {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS}, - {"size", (PyCFunction) mmap_size_method, METH_NOARGS}, - {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS}, - {"write", (PyCFunction) mmap_write_method, METH_VARARGS}, - {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS}, - {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS}, - {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS}, -#ifdef MS_WINDOWS - {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS}, -#endif - {NULL, NULL} /* sentinel */ -}; - -static PyGetSetDef mmap_object_getset[] = { - {"closed", (getter) mmap_closed_get, NULL, NULL}, - {NULL} -}; - - -/* Functions for treating an mmap'ed file as a buffer */ - -static int -mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags) -{ - CHECK_VALID(-1); - if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size, - (self->access == ACCESS_READ), flags) < 0) - return -1; - self->exports++; - return 0; -} - -static void -mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view) -{ - self->exports--; -} - -static Py_ssize_t -mmap_length(mmap_object *self) -{ - CHECK_VALID(-1); - return self->size; -} - -static PyObject * -mmap_item(mmap_object *self, Py_ssize_t i) -{ - CHECK_VALID(NULL); - if (i < 0 || i >= self->size) { - PyErr_SetString(PyExc_IndexError, "mmap index out of range"); - return NULL; - } - return PyBytes_FromStringAndSize(self->data + i, 1); -} - -static PyObject * -mmap_subscript(mmap_object *self, PyObject *item) -{ - CHECK_VALID(NULL); - if (PyIndex_Check(item)) { - Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return NULL; - if (i < 0) - i += self->size; - if (i < 0 || i >= self->size) { - PyErr_SetString(PyExc_IndexError, - "mmap index out of range"); - return NULL; - } - return PyLong_FromLong(Py_CHARMASK(self->data[i])); - } - else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelen; - - if (PySlice_Unpack(item, &start, &stop, &step) < 0) { - return NULL; - } - slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step); - - if (slicelen <= 0) - return PyBytes_FromStringAndSize("", 0); - else if (step == 1) - return PyBytes_FromStringAndSize(self->data + start, - slicelen); - else { - char *result_buf = (char *)PyMem_Malloc(slicelen); + {"move", (PyCFunction) mmap_move_method, METH_VARARGS}, + {"read", (PyCFunction) mmap_read_method, METH_VARARGS}, + {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS}, + {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS}, + {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS}, + {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS}, + {"size", (PyCFunction) mmap_size_method, METH_NOARGS}, + {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS}, + {"write", (PyCFunction) mmap_write_method, METH_VARARGS}, + {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS}, + {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS}, + {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS}, +#ifdef MS_WINDOWS + {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS}, +#endif + {NULL, NULL} /* sentinel */ +}; + +static PyGetSetDef mmap_object_getset[] = { + {"closed", (getter) mmap_closed_get, NULL, NULL}, + {NULL} +}; + + +/* Functions for treating an mmap'ed file as a buffer */ + +static int +mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags) +{ + CHECK_VALID(-1); + if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size, + (self->access == ACCESS_READ), flags) < 0) + return -1; + self->exports++; + return 0; +} + +static void +mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view) +{ + self->exports--; +} + +static Py_ssize_t +mmap_length(mmap_object *self) +{ + CHECK_VALID(-1); + return self->size; +} + +static PyObject * +mmap_item(mmap_object *self, Py_ssize_t i) +{ + CHECK_VALID(NULL); + if (i < 0 || i >= self->size) { + PyErr_SetString(PyExc_IndexError, "mmap index out of range"); + return NULL; + } + return PyBytes_FromStringAndSize(self->data + i, 1); +} + +static PyObject * +mmap_subscript(mmap_object *self, PyObject *item) +{ + CHECK_VALID(NULL); + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += self->size; + if (i < 0 || i >= self->size) { + PyErr_SetString(PyExc_IndexError, + "mmap index out of range"); + return NULL; + } + return PyLong_FromLong(Py_CHARMASK(self->data[i])); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelen; + + if (PySlice_Unpack(item, &start, &stop, &step) < 0) { + return NULL; + } + slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step); + + if (slicelen <= 0) + return PyBytes_FromStringAndSize("", 0); + else if (step == 1) + return PyBytes_FromStringAndSize(self->data + start, + slicelen); + else { + char *result_buf = (char *)PyMem_Malloc(slicelen); size_t cur; Py_ssize_t i; - PyObject *result; - - if (result_buf == NULL) - return PyErr_NoMemory(); - for (cur = start, i = 0; i < slicelen; - cur += step, i++) { - result_buf[i] = self->data[cur]; - } - result = PyBytes_FromStringAndSize(result_buf, - slicelen); - PyMem_Free(result_buf); - return result; - } - } - else { - PyErr_SetString(PyExc_TypeError, - "mmap indices must be integers"); - return NULL; - } -} - -static int -mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v) -{ - const char *buf; - - CHECK_VALID(-1); - if (i < 0 || i >= self->size) { - PyErr_SetString(PyExc_IndexError, "mmap index out of range"); - return -1; - } - if (v == NULL) { - PyErr_SetString(PyExc_TypeError, - "mmap object doesn't support item deletion"); - return -1; - } - if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) { - PyErr_SetString(PyExc_IndexError, - "mmap assignment must be length-1 bytes()"); - return -1; - } - if (!is_writable(self)) - return -1; - buf = PyBytes_AsString(v); - self->data[i] = buf[0]; - return 0; -} - -static int -mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value) -{ - CHECK_VALID(-1); - - if (!is_writable(self)) - return -1; - - if (PyIndex_Check(item)) { - Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); - Py_ssize_t v; - - if (i == -1 && PyErr_Occurred()) - return -1; - if (i < 0) - i += self->size; - if (i < 0 || i >= self->size) { - PyErr_SetString(PyExc_IndexError, - "mmap index out of range"); - return -1; - } - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, - "mmap doesn't support item deletion"); - return -1; - } - if (!PyIndex_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "mmap item value must be an int"); - return -1; - } - v = PyNumber_AsSsize_t(value, PyExc_TypeError); - if (v == -1 && PyErr_Occurred()) - return -1; - if (v < 0 || v > 255) { - PyErr_SetString(PyExc_ValueError, - "mmap item value must be " - "in range(0, 256)"); - return -1; - } - self->data[i] = (char) v; - return 0; - } - else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelen; - Py_buffer vbuf; - - if (PySlice_Unpack(item, &start, &stop, &step) < 0) { - return -1; - } - slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step); - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, - "mmap object doesn't support slice deletion"); - return -1; - } - if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0) - return -1; - if (vbuf.len != slicelen) { - PyErr_SetString(PyExc_IndexError, - "mmap slice assignment is wrong size"); - PyBuffer_Release(&vbuf); - return -1; - } - - if (slicelen == 0) { - } - else if (step == 1) { - memcpy(self->data + start, vbuf.buf, slicelen); - } - else { + PyObject *result; + + if (result_buf == NULL) + return PyErr_NoMemory(); + for (cur = start, i = 0; i < slicelen; + cur += step, i++) { + result_buf[i] = self->data[cur]; + } + result = PyBytes_FromStringAndSize(result_buf, + slicelen); + PyMem_Free(result_buf); + return result; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "mmap indices must be integers"); + return NULL; + } +} + +static int +mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v) +{ + const char *buf; + + CHECK_VALID(-1); + if (i < 0 || i >= self->size) { + PyErr_SetString(PyExc_IndexError, "mmap index out of range"); + return -1; + } + if (v == NULL) { + PyErr_SetString(PyExc_TypeError, + "mmap object doesn't support item deletion"); + return -1; + } + if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) { + PyErr_SetString(PyExc_IndexError, + "mmap assignment must be length-1 bytes()"); + return -1; + } + if (!is_writable(self)) + return -1; + buf = PyBytes_AsString(v); + self->data[i] = buf[0]; + return 0; +} + +static int +mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value) +{ + CHECK_VALID(-1); + + if (!is_writable(self)) + return -1; + + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + Py_ssize_t v; + + if (i == -1 && PyErr_Occurred()) + return -1; + if (i < 0) + i += self->size; + if (i < 0 || i >= self->size) { + PyErr_SetString(PyExc_IndexError, + "mmap index out of range"); + return -1; + } + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "mmap doesn't support item deletion"); + return -1; + } + if (!PyIndex_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "mmap item value must be an int"); + return -1; + } + v = PyNumber_AsSsize_t(value, PyExc_TypeError); + if (v == -1 && PyErr_Occurred()) + return -1; + if (v < 0 || v > 255) { + PyErr_SetString(PyExc_ValueError, + "mmap item value must be " + "in range(0, 256)"); + return -1; + } + self->data[i] = (char) v; + return 0; + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelen; + Py_buffer vbuf; + + if (PySlice_Unpack(item, &start, &stop, &step) < 0) { + return -1; + } + slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step); + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "mmap object doesn't support slice deletion"); + return -1; + } + if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0) + return -1; + if (vbuf.len != slicelen) { + PyErr_SetString(PyExc_IndexError, + "mmap slice assignment is wrong size"); + PyBuffer_Release(&vbuf); + return -1; + } + + if (slicelen == 0) { + } + else if (step == 1) { + memcpy(self->data + start, vbuf.buf, slicelen); + } + else { size_t cur; Py_ssize_t i; - - for (cur = start, i = 0; - i < slicelen; - cur += step, i++) - { - self->data[cur] = ((char *)vbuf.buf)[i]; - } - } - PyBuffer_Release(&vbuf); - return 0; - } - else { - PyErr_SetString(PyExc_TypeError, - "mmap indices must be integer"); - return -1; - } -} - -static PySequenceMethods mmap_as_sequence = { - (lenfunc)mmap_length, /*sq_length*/ - 0, /*sq_concat*/ - 0, /*sq_repeat*/ - (ssizeargfunc)mmap_item, /*sq_item*/ - 0, /*sq_slice*/ - (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/ - 0, /*sq_ass_slice*/ -}; - -static PyMappingMethods mmap_as_mapping = { - (lenfunc)mmap_length, - (binaryfunc)mmap_subscript, - (objobjargproc)mmap_ass_subscript, -}; - -static PyBufferProcs mmap_as_buffer = { - (getbufferproc)mmap_buffer_getbuf, - (releasebufferproc)mmap_buffer_releasebuf, -}; - -static PyObject * -new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict); - -PyDoc_STRVAR(mmap_doc, -"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\ -\n\ -Maps length bytes from the file specified by the file handle fileno,\n\ -and returns a mmap object. If length is larger than the current size\n\ -of the file, the file is extended to contain length bytes. If length\n\ -is 0, the maximum length of the map is the current size of the file,\n\ -except that if the file is empty Windows raises an exception (you cannot\n\ -create an empty mapping on Windows).\n\ -\n\ -Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\ -\n\ -Maps length bytes from the file specified by the file descriptor fileno,\n\ -and returns a mmap object. If length is 0, the maximum length of the map\n\ -will be the current size of the file when mmap is called.\n\ -flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\ -private copy-on-write mapping, so changes to the contents of the mmap\n\ -object will be private to this process, and MAP_SHARED creates a mapping\n\ -that's shared with all other processes mapping the same areas of the file.\n\ -The default value is MAP_SHARED.\n\ -\n\ -To map anonymous memory, pass -1 as the fileno (both versions)."); - - -static PyTypeObject mmap_object_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "mmap.mmap", /* tp_name */ - sizeof(mmap_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ + + for (cur = start, i = 0; + i < slicelen; + cur += step, i++) + { + self->data[cur] = ((char *)vbuf.buf)[i]; + } + } + PyBuffer_Release(&vbuf); + return 0; + } + else { + PyErr_SetString(PyExc_TypeError, + "mmap indices must be integer"); + return -1; + } +} + +static PySequenceMethods mmap_as_sequence = { + (lenfunc)mmap_length, /*sq_length*/ + 0, /*sq_concat*/ + 0, /*sq_repeat*/ + (ssizeargfunc)mmap_item, /*sq_item*/ + 0, /*sq_slice*/ + (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/ + 0, /*sq_ass_slice*/ +}; + +static PyMappingMethods mmap_as_mapping = { + (lenfunc)mmap_length, + (binaryfunc)mmap_subscript, + (objobjargproc)mmap_ass_subscript, +}; + +static PyBufferProcs mmap_as_buffer = { + (getbufferproc)mmap_buffer_getbuf, + (releasebufferproc)mmap_buffer_releasebuf, +}; + +static PyObject * +new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict); + +PyDoc_STRVAR(mmap_doc, +"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\ +\n\ +Maps length bytes from the file specified by the file handle fileno,\n\ +and returns a mmap object. If length is larger than the current size\n\ +of the file, the file is extended to contain length bytes. If length\n\ +is 0, the maximum length of the map is the current size of the file,\n\ +except that if the file is empty Windows raises an exception (you cannot\n\ +create an empty mapping on Windows).\n\ +\n\ +Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\ +\n\ +Maps length bytes from the file specified by the file descriptor fileno,\n\ +and returns a mmap object. If length is 0, the maximum length of the map\n\ +will be the current size of the file when mmap is called.\n\ +flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\ +private copy-on-write mapping, so changes to the contents of the mmap\n\ +object will be private to this process, and MAP_SHARED creates a mapping\n\ +that's shared with all other processes mapping the same areas of the file.\n\ +The default value is MAP_SHARED.\n\ +\n\ +To map anonymous memory, pass -1 as the fileno (both versions)."); + + +static PyTypeObject mmap_object_type = { + PyVarObject_HEAD_INIT(NULL, 0) + "mmap.mmap", /* tp_name */ + sizeof(mmap_object), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ (destructor)mmap_object_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ 0, /* tp_as_async */ (reprfunc)mmap__repr__method, /* tp_repr */ - 0, /* tp_as_number */ + 0, /* tp_as_number */ &mmap_as_sequence, /* tp_as_sequence */ &mmap_as_mapping, /* tp_as_mapping */ 0, /* tp_hash */ @@ -1106,157 +1106,157 @@ static PyTypeObject mmap_object_type = { &mmap_as_buffer, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ mmap_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(mmap_object, weakreflist), /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - mmap_object_methods, /* tp_methods */ - 0, /* tp_members */ - mmap_object_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - new_mmap_object, /* tp_new */ - PyObject_Del, /* tp_free */ -}; - - -#ifdef UNIX -#ifdef HAVE_LARGEFILE_SUPPORT -#define _Py_PARSE_OFF_T "L" -#else -#define _Py_PARSE_OFF_T "l" -#endif - -static PyObject * -new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) -{ - struct _Py_stat_struct status; - int fstat_result = -1; - mmap_object *m_obj; - Py_ssize_t map_size; - off_t offset = 0; - int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ; - int devzero = -1; - int access = (int)ACCESS_DEFAULT; - static char *keywords[] = {"fileno", "length", - "flags", "prot", - "access", "offset", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords, - &fd, &map_size, &flags, &prot, - &access, &offset)) - return NULL; - if (map_size < 0) { - PyErr_SetString(PyExc_OverflowError, - "memory mapped length must be positive"); - return NULL; - } - if (offset < 0) { - PyErr_SetString(PyExc_OverflowError, - "memory mapped offset must be positive"); - return NULL; - } - - if ((access != (int)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_mode)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: - /* map prot to access type */ - if ((prot & PROT_READ) && (prot & PROT_WRITE)) { - /* ACCESS_DEFAULT */ - } - else if (prot & PROT_WRITE) { - access = ACCESS_WRITE; - } - else { - access = ACCESS_READ; - } - break; - default: - return PyErr_Format(PyExc_ValueError, - "mmap invalid access parameter."); - } - + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(mmap_object, weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + mmap_object_methods, /* tp_methods */ + 0, /* tp_members */ + mmap_object_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + new_mmap_object, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + + +#ifdef UNIX +#ifdef HAVE_LARGEFILE_SUPPORT +#define _Py_PARSE_OFF_T "L" +#else +#define _Py_PARSE_OFF_T "l" +#endif + +static PyObject * +new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) +{ + struct _Py_stat_struct status; + int fstat_result = -1; + mmap_object *m_obj; + Py_ssize_t map_size; + off_t offset = 0; + int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ; + int devzero = -1; + int access = (int)ACCESS_DEFAULT; + static char *keywords[] = {"fileno", "length", + "flags", "prot", + "access", "offset", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords, + &fd, &map_size, &flags, &prot, + &access, &offset)) + return NULL; + if (map_size < 0) { + PyErr_SetString(PyExc_OverflowError, + "memory mapped length must be positive"); + return NULL; + } + if (offset < 0) { + PyErr_SetString(PyExc_OverflowError, + "memory mapped offset must be positive"); + return NULL; + } + + if ((access != (int)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_mode)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: + /* map prot to access type */ + if ((prot & PROT_READ) && (prot & PROT_WRITE)) { + /* ACCESS_DEFAULT */ + } + else if (prot & PROT_WRITE) { + access = ACCESS_WRITE; + } + else { + access = ACCESS_READ; + } + break; + default: + return PyErr_Format(PyExc_ValueError, + "mmap invalid access parameter."); + } + if (PySys_Audit("mmap.__new__", "ini" _Py_PARSE_OFF_T, fd, map_size, access, offset) < 0) { return NULL; } -#ifdef __APPLE__ - /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific - fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */ - if (fd != -1) - (void)fcntl(fd, F_FULLFSYNC); -#endif - - if (fd != -1) { - Py_BEGIN_ALLOW_THREADS - fstat_result = _Py_fstat_noraise(fd, &status); - Py_END_ALLOW_THREADS - } - - if (fd != -1 && fstat_result == 0 && S_ISREG(status.st_mode)) { - if (map_size == 0) { - if (status.st_size == 0) { - PyErr_SetString(PyExc_ValueError, - "cannot mmap an empty file"); - return NULL; - } - if (offset >= status.st_size) { - PyErr_SetString(PyExc_ValueError, - "mmap offset is greater than file size"); - return NULL; - } - if (status.st_size - offset > PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_ValueError, - "mmap length is too large"); - return NULL; - } - map_size = (Py_ssize_t) (status.st_size - offset); - } else if (offset > status.st_size || status.st_size - offset < map_size) { - PyErr_SetString(PyExc_ValueError, - "mmap length is greater than file size"); - return NULL; - } - } - m_obj = (mmap_object *)type->tp_alloc(type, 0); - if (m_obj == NULL) {return NULL;} - m_obj->data = NULL; - m_obj->size = map_size; - m_obj->pos = 0; - m_obj->weakreflist = NULL; - m_obj->exports = 0; - m_obj->offset = offset; - if (fd == -1) { - m_obj->fd = -1; - /* Assume the caller wants to map anonymous memory. - This is the same behaviour as Windows. mmap.mmap(-1, size) - on both Windows and Unix map anonymous memory. - */ -#ifdef MAP_ANONYMOUS - /* BSD way to map anonymous memory */ - flags |= MAP_ANONYMOUS; +#ifdef __APPLE__ + /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific + fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */ + if (fd != -1) + (void)fcntl(fd, F_FULLFSYNC); +#endif + + if (fd != -1) { + Py_BEGIN_ALLOW_THREADS + fstat_result = _Py_fstat_noraise(fd, &status); + Py_END_ALLOW_THREADS + } + + if (fd != -1 && fstat_result == 0 && S_ISREG(status.st_mode)) { + if (map_size == 0) { + if (status.st_size == 0) { + PyErr_SetString(PyExc_ValueError, + "cannot mmap an empty file"); + return NULL; + } + if (offset >= status.st_size) { + PyErr_SetString(PyExc_ValueError, + "mmap offset is greater than file size"); + return NULL; + } + if (status.st_size - offset > PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_ValueError, + "mmap length is too large"); + return NULL; + } + map_size = (Py_ssize_t) (status.st_size - offset); + } else if (offset > status.st_size || status.st_size - offset < map_size) { + PyErr_SetString(PyExc_ValueError, + "mmap length is greater than file size"); + return NULL; + } + } + m_obj = (mmap_object *)type->tp_alloc(type, 0); + if (m_obj == NULL) {return NULL;} + m_obj->data = NULL; + m_obj->size = map_size; + m_obj->pos = 0; + m_obj->weakreflist = NULL; + m_obj->exports = 0; + m_obj->offset = offset; + if (fd == -1) { + m_obj->fd = -1; + /* Assume the caller wants to map anonymous memory. + This is the same behaviour as Windows. mmap.mmap(-1, size) + on both Windows and Unix map anonymous memory. + */ +#ifdef MAP_ANONYMOUS + /* BSD way to map anonymous memory */ + flags |= MAP_ANONYMOUS; /* VxWorks only supports MAP_ANONYMOUS with MAP_PRIVATE flag */ #ifdef __VXWORKS__ @@ -1264,325 +1264,325 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) flags |= MAP_PRIVATE; #endif -#else - /* SVR4 method to map anonymous memory is to open /dev/zero */ - fd = devzero = _Py_open("/dev/zero", O_RDWR); - if (devzero == -1) { - Py_DECREF(m_obj); - return NULL; - } -#endif - } - else { - m_obj->fd = _Py_dup(fd); - if (m_obj->fd == -1) { - Py_DECREF(m_obj); - return NULL; - } - } - - m_obj->data = mmap(NULL, map_size, - prot, flags, - fd, offset); - - if (devzero != -1) { - close(devzero); - } - - if (m_obj->data == (char *)-1) { - m_obj->data = NULL; - Py_DECREF(m_obj); - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - m_obj->access = (access_mode)access; - return (PyObject *)m_obj; -} -#endif /* UNIX */ - -#ifdef MS_WINDOWS - -/* A note on sizes and offsets: while the actual map size must hold in a - Py_ssize_t, both the total file size and the start offset can be longer - than a Py_ssize_t, so we use long long which is always 64-bit. -*/ - -static PyObject * -new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) -{ - mmap_object *m_obj; - Py_ssize_t map_size; - long long offset = 0, size; - DWORD off_hi; /* upper 32 bits of offset */ - DWORD off_lo; /* lower 32 bits of offset */ - DWORD size_hi; /* upper 32 bits of size */ - DWORD size_lo; /* lower 32 bits of size */ - const char *tagname = ""; - DWORD dwErr = 0; - int fileno; - HANDLE fh = 0; - int access = (access_mode)ACCESS_DEFAULT; - DWORD flProtect, dwDesiredAccess; - static char *keywords[] = { "fileno", "length", - "tagname", - "access", "offset", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords, - &fileno, &map_size, - &tagname, &access, &offset)) { - return NULL; - } - +#else + /* SVR4 method to map anonymous memory is to open /dev/zero */ + fd = devzero = _Py_open("/dev/zero", O_RDWR); + if (devzero == -1) { + Py_DECREF(m_obj); + return NULL; + } +#endif + } + else { + m_obj->fd = _Py_dup(fd); + if (m_obj->fd == -1) { + Py_DECREF(m_obj); + return NULL; + } + } + + m_obj->data = mmap(NULL, map_size, + prot, flags, + fd, offset); + + if (devzero != -1) { + close(devzero); + } + + if (m_obj->data == (char *)-1) { + m_obj->data = NULL; + Py_DECREF(m_obj); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + m_obj->access = (access_mode)access; + return (PyObject *)m_obj; +} +#endif /* UNIX */ + +#ifdef MS_WINDOWS + +/* A note on sizes and offsets: while the actual map size must hold in a + Py_ssize_t, both the total file size and the start offset can be longer + than a Py_ssize_t, so we use long long which is always 64-bit. +*/ + +static PyObject * +new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) +{ + mmap_object *m_obj; + Py_ssize_t map_size; + long long offset = 0, size; + DWORD off_hi; /* upper 32 bits of offset */ + DWORD off_lo; /* lower 32 bits of offset */ + DWORD size_hi; /* upper 32 bits of size */ + DWORD size_lo; /* lower 32 bits of size */ + const char *tagname = ""; + DWORD dwErr = 0; + int fileno; + HANDLE fh = 0; + int access = (access_mode)ACCESS_DEFAULT; + DWORD flProtect, dwDesiredAccess; + static char *keywords[] = { "fileno", "length", + "tagname", + "access", "offset", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords, + &fileno, &map_size, + &tagname, &access, &offset)) { + return NULL; + } + if (PySys_Audit("mmap.__new__", "iniL", fileno, map_size, access, offset) < 0) { return NULL; } - switch((access_mode)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."); - } - - if (map_size < 0) { - PyErr_SetString(PyExc_OverflowError, - "memory mapped length must be positive"); - return NULL; - } - if (offset < 0) { - PyErr_SetString(PyExc_OverflowError, - "memory mapped offset must be positive"); - return NULL; - } - - /* assume -1 and 0 both mean invalid filedescriptor - to 'anonymously' map memory. - XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5. - XXX: Should this code be added? - if (fileno == 0) - PyErr_WarnEx(PyExc_DeprecationWarning, - "don't use 0 for anonymous memory", - 1); - */ - if (fileno != -1 && fileno != 0) { - /* Ensure that fileno is within the CRT's valid range */ - _Py_BEGIN_SUPPRESS_IPH - fh = (HANDLE)_get_osfhandle(fileno); - _Py_END_SUPPRESS_IPH - if (fh==(HANDLE)-1) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - /* Win9x appears to need us seeked to zero */ - lseek(fileno, 0, SEEK_SET); - } - - m_obj = (mmap_object *)type->tp_alloc(type, 0); - if (m_obj == NULL) - return NULL; - /* Set every field to an invalid marker, so we can safely - destruct the object in the face of failure */ - m_obj->data = NULL; - m_obj->file_handle = INVALID_HANDLE_VALUE; - m_obj->map_handle = NULL; - m_obj->tagname = NULL; - m_obj->offset = offset; - - if (fh) { - /* 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 */ - dwErr = GetLastError(); - Py_DECREF(m_obj); - PyErr_SetFromWindowsErr(dwErr); - return NULL; - } - if (!map_size) { - DWORD low,high; - low = GetFileSize(fh, &high); - /* low might just happen to have the value INVALID_FILE_SIZE; - so we need to check the last error also. */ - if (low == INVALID_FILE_SIZE && - (dwErr = GetLastError()) != NO_ERROR) { - Py_DECREF(m_obj); - return PyErr_SetFromWindowsErr(dwErr); - } - - size = (((long long) high) << 32) + low; - if (size == 0) { - PyErr_SetString(PyExc_ValueError, - "cannot mmap an empty file"); - Py_DECREF(m_obj); - return NULL; - } - if (offset >= size) { - PyErr_SetString(PyExc_ValueError, - "mmap offset is greater than file size"); - Py_DECREF(m_obj); - return NULL; - } - if (size - offset > PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_ValueError, - "mmap length is too large"); - Py_DECREF(m_obj); - return NULL; - } - m_obj->size = (Py_ssize_t) (size - offset); - } else { - m_obj->size = map_size; - size = offset + map_size; - } - } - else { - m_obj->size = map_size; - size = offset + map_size; - } - - /* set the initial position */ - m_obj->pos = (size_t) 0; - - m_obj->weakreflist = NULL; - m_obj->exports = 0; - /* set the tag name */ - if (tagname != NULL && *tagname != '\0') { - m_obj->tagname = PyMem_Malloc(strlen(tagname)+1); - if (m_obj->tagname == NULL) { - PyErr_NoMemory(); - Py_DECREF(m_obj); - return NULL; - } - strcpy(m_obj->tagname, tagname); - } - else - m_obj->tagname = NULL; - - m_obj->access = (access_mode)access; - size_hi = (DWORD)(size >> 32); - size_lo = (DWORD)(size & 0xFFFFFFFF); - off_hi = (DWORD)(offset >> 32); - off_lo = (DWORD)(offset & 0xFFFFFFFF); - /* For files, it would be sufficient to pass 0 as size. - For anonymous maps, we have to pass the size explicitly. */ - m_obj->map_handle = CreateFileMapping(m_obj->file_handle, - NULL, - flProtect, - size_hi, - size_lo, - m_obj->tagname); - if (m_obj->map_handle != NULL) { - m_obj->data = (char *) MapViewOfFile(m_obj->map_handle, - dwDesiredAccess, - off_hi, - off_lo, - m_obj->size); - if (m_obj->data != NULL) - return (PyObject *)m_obj; - else { - dwErr = GetLastError(); - CloseHandle(m_obj->map_handle); - m_obj->map_handle = NULL; - } - } else - dwErr = GetLastError(); - Py_DECREF(m_obj); - PyErr_SetFromWindowsErr(dwErr); - return NULL; -} -#endif /* MS_WINDOWS */ - -static void -setint(PyObject *d, const char *name, long value) -{ - PyObject *o = PyLong_FromLong(value); + switch((access_mode)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."); + } + + if (map_size < 0) { + PyErr_SetString(PyExc_OverflowError, + "memory mapped length must be positive"); + return NULL; + } + if (offset < 0) { + PyErr_SetString(PyExc_OverflowError, + "memory mapped offset must be positive"); + return NULL; + } + + /* assume -1 and 0 both mean invalid filedescriptor + to 'anonymously' map memory. + XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5. + XXX: Should this code be added? + if (fileno == 0) + PyErr_WarnEx(PyExc_DeprecationWarning, + "don't use 0 for anonymous memory", + 1); + */ + if (fileno != -1 && fileno != 0) { + /* Ensure that fileno is within the CRT's valid range */ + _Py_BEGIN_SUPPRESS_IPH + fh = (HANDLE)_get_osfhandle(fileno); + _Py_END_SUPPRESS_IPH + if (fh==(HANDLE)-1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + /* Win9x appears to need us seeked to zero */ + lseek(fileno, 0, SEEK_SET); + } + + m_obj = (mmap_object *)type->tp_alloc(type, 0); + if (m_obj == NULL) + return NULL; + /* Set every field to an invalid marker, so we can safely + destruct the object in the face of failure */ + m_obj->data = NULL; + m_obj->file_handle = INVALID_HANDLE_VALUE; + m_obj->map_handle = NULL; + m_obj->tagname = NULL; + m_obj->offset = offset; + + if (fh) { + /* 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 */ + dwErr = GetLastError(); + Py_DECREF(m_obj); + PyErr_SetFromWindowsErr(dwErr); + return NULL; + } + if (!map_size) { + DWORD low,high; + low = GetFileSize(fh, &high); + /* low might just happen to have the value INVALID_FILE_SIZE; + so we need to check the last error also. */ + if (low == INVALID_FILE_SIZE && + (dwErr = GetLastError()) != NO_ERROR) { + Py_DECREF(m_obj); + return PyErr_SetFromWindowsErr(dwErr); + } + + size = (((long long) high) << 32) + low; + if (size == 0) { + PyErr_SetString(PyExc_ValueError, + "cannot mmap an empty file"); + Py_DECREF(m_obj); + return NULL; + } + if (offset >= size) { + PyErr_SetString(PyExc_ValueError, + "mmap offset is greater than file size"); + Py_DECREF(m_obj); + return NULL; + } + if (size - offset > PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_ValueError, + "mmap length is too large"); + Py_DECREF(m_obj); + return NULL; + } + m_obj->size = (Py_ssize_t) (size - offset); + } else { + m_obj->size = map_size; + size = offset + map_size; + } + } + else { + m_obj->size = map_size; + size = offset + map_size; + } + + /* set the initial position */ + m_obj->pos = (size_t) 0; + + m_obj->weakreflist = NULL; + m_obj->exports = 0; + /* set the tag name */ + if (tagname != NULL && *tagname != '\0') { + m_obj->tagname = PyMem_Malloc(strlen(tagname)+1); + if (m_obj->tagname == NULL) { + PyErr_NoMemory(); + Py_DECREF(m_obj); + return NULL; + } + strcpy(m_obj->tagname, tagname); + } + else + m_obj->tagname = NULL; + + m_obj->access = (access_mode)access; + size_hi = (DWORD)(size >> 32); + size_lo = (DWORD)(size & 0xFFFFFFFF); + off_hi = (DWORD)(offset >> 32); + off_lo = (DWORD)(offset & 0xFFFFFFFF); + /* For files, it would be sufficient to pass 0 as size. + For anonymous maps, we have to pass the size explicitly. */ + m_obj->map_handle = CreateFileMapping(m_obj->file_handle, + NULL, + flProtect, + size_hi, + size_lo, + m_obj->tagname); + if (m_obj->map_handle != NULL) { + m_obj->data = (char *) MapViewOfFile(m_obj->map_handle, + dwDesiredAccess, + off_hi, + off_lo, + m_obj->size); + if (m_obj->data != NULL) + return (PyObject *)m_obj; + else { + dwErr = GetLastError(); + CloseHandle(m_obj->map_handle); + m_obj->map_handle = NULL; + } + } else + dwErr = GetLastError(); + Py_DECREF(m_obj); + PyErr_SetFromWindowsErr(dwErr); + return NULL; +} +#endif /* MS_WINDOWS */ + +static void +setint(PyObject *d, const char *name, long value) +{ + PyObject *o = PyLong_FromLong(value); if (o) { PyDict_SetItemString(d, name, o); - Py_DECREF(o); - } -} - - -static struct PyModuleDef mmapmodule = { - PyModuleDef_HEAD_INIT, - "mmap", - NULL, - -1, - NULL, - NULL, - NULL, - NULL, - NULL -}; - -PyMODINIT_FUNC -PyInit_mmap(void) -{ - PyObject *dict, *module; - - if (PyType_Ready(&mmap_object_type) < 0) - return NULL; - - module = PyModule_Create(&mmapmodule); - if (module == NULL) - return NULL; - dict = PyModule_GetDict(module); - if (!dict) - return NULL; - PyDict_SetItemString(dict, "error", PyExc_OSError); - PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type); -#ifdef PROT_EXEC - setint(dict, "PROT_EXEC", PROT_EXEC); -#endif -#ifdef PROT_READ - setint(dict, "PROT_READ", PROT_READ); -#endif -#ifdef PROT_WRITE - setint(dict, "PROT_WRITE", PROT_WRITE); -#endif - -#ifdef MAP_SHARED - setint(dict, "MAP_SHARED", MAP_SHARED); -#endif -#ifdef MAP_PRIVATE - setint(dict, "MAP_PRIVATE", MAP_PRIVATE); -#endif -#ifdef MAP_DENYWRITE - setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE); -#endif -#ifdef MAP_EXECUTABLE - setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE); -#endif -#ifdef MAP_ANONYMOUS - setint(dict, "MAP_ANON", MAP_ANONYMOUS); - setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS); -#endif - - setint(dict, "PAGESIZE", (long)my_getpagesize()); - - setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity()); - - setint(dict, "ACCESS_DEFAULT", ACCESS_DEFAULT); - setint(dict, "ACCESS_READ", ACCESS_READ); - setint(dict, "ACCESS_WRITE", ACCESS_WRITE); - setint(dict, "ACCESS_COPY", ACCESS_COPY); + Py_DECREF(o); + } +} + + +static struct PyModuleDef mmapmodule = { + PyModuleDef_HEAD_INIT, + "mmap", + NULL, + -1, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC +PyInit_mmap(void) +{ + PyObject *dict, *module; + + if (PyType_Ready(&mmap_object_type) < 0) + return NULL; + + module = PyModule_Create(&mmapmodule); + if (module == NULL) + return NULL; + dict = PyModule_GetDict(module); + if (!dict) + return NULL; + PyDict_SetItemString(dict, "error", PyExc_OSError); + PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type); +#ifdef PROT_EXEC + setint(dict, "PROT_EXEC", PROT_EXEC); +#endif +#ifdef PROT_READ + setint(dict, "PROT_READ", PROT_READ); +#endif +#ifdef PROT_WRITE + setint(dict, "PROT_WRITE", PROT_WRITE); +#endif + +#ifdef MAP_SHARED + setint(dict, "MAP_SHARED", MAP_SHARED); +#endif +#ifdef MAP_PRIVATE + setint(dict, "MAP_PRIVATE", MAP_PRIVATE); +#endif +#ifdef MAP_DENYWRITE + setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE); +#endif +#ifdef MAP_EXECUTABLE + setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE); +#endif +#ifdef MAP_ANONYMOUS + setint(dict, "MAP_ANON", MAP_ANONYMOUS); + setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS); +#endif + + setint(dict, "PAGESIZE", (long)my_getpagesize()); + + setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity()); + + setint(dict, "ACCESS_DEFAULT", ACCESS_DEFAULT); + setint(dict, "ACCESS_READ", ACCESS_READ); + setint(dict, "ACCESS_WRITE", ACCESS_WRITE); + setint(dict, "ACCESS_COPY", ACCESS_COPY); #ifdef HAVE_MADVISE // Conventional advice values @@ -1658,5 +1658,5 @@ PyInit_mmap(void) #endif #endif // HAVE_MADVISE - return module; -} + return module; +} |
