Home | History | Annotate | Download | only in Modules
      1 /*
      2  /  Author: Sam Rushing <rushing (at) nightmare.com>
      3  /  Hacked for Unix by AMK
      4  /  $Id$
      5 
      6  / Modified to support mmap with offset - to map a 'window' of a file
      7  /   Author:  Yotam Medini  yotamm (at) mellanox.co.il
      8  /
      9  / mmapmodule.cpp -- map a view of a file into memory
     10  /
     11  / todo: need permission flags, perhaps a 'chsize' analog
     12  /   not all functions check range yet!!!
     13  /
     14  /
     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.
     19 */
     20 
     21 #define PY_SSIZE_T_CLEAN
     22 #include <Python.h>
     23 
     24 #ifndef MS_WINDOWS
     25 #define UNIX
     26 # ifdef HAVE_FCNTL_H
     27 #  include <fcntl.h>
     28 # endif /* HAVE_FCNTL_H */
     29 #endif
     30 
     31 #ifdef MS_WINDOWS
     32 #include <windows.h>
     33 static int
     34 my_getpagesize(void)
     35 {
     36     SYSTEM_INFO si;
     37     GetSystemInfo(&si);
     38     return si.dwPageSize;
     39 }
     40 
     41 static int
     42 my_getallocationgranularity (void)
     43 {
     44 
     45     SYSTEM_INFO si;
     46     GetSystemInfo(&si);
     47     return si.dwAllocationGranularity;
     48 }
     49 
     50 #endif
     51 
     52 #ifdef UNIX
     53 #include <sys/mman.h>
     54 #include <sys/stat.h>
     55 
     56 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
     57 static int
     58 my_getpagesize(void)
     59 {
     60     return sysconf(_SC_PAGESIZE);
     61 }
     62 
     63 #define my_getallocationgranularity my_getpagesize
     64 #else
     65 #define my_getpagesize getpagesize
     66 #endif
     67 
     68 #endif /* UNIX */
     69 
     70 #include <string.h>
     71 
     72 #ifdef HAVE_SYS_TYPES_H
     73 #include <sys/types.h>
     74 #endif /* HAVE_SYS_TYPES_H */
     75 
     76 /* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
     77 #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
     78 #  define MAP_ANONYMOUS MAP_ANON
     79 #endif
     80 
     81 static PyObject *mmap_module_error;
     82 
     83 typedef enum
     84 {
     85     ACCESS_DEFAULT,
     86     ACCESS_READ,
     87     ACCESS_WRITE,
     88     ACCESS_COPY
     89 } access_mode;
     90 
     91 typedef struct {
     92     PyObject_HEAD
     93     char *      data;
     94     Py_ssize_t  size;
     95     Py_ssize_t  pos;    /* relative to offset */
     96 #ifdef MS_WINDOWS
     97     PY_LONG_LONG offset;
     98 #else
     99     off_t       offset;
    100 #endif
    101 
    102 #ifdef MS_WINDOWS
    103     HANDLE      map_handle;
    104     HANDLE      file_handle;
    105     char *      tagname;
    106 #endif
    107 
    108 #ifdef UNIX
    109     int fd;
    110 #endif
    111 
    112     access_mode access;
    113 } mmap_object;
    114 
    115 
    116 static void
    117 mmap_object_dealloc(mmap_object *m_obj)
    118 {
    119 #ifdef MS_WINDOWS
    120     if (m_obj->data != NULL)
    121         UnmapViewOfFile (m_obj->data);
    122     if (m_obj->map_handle != NULL)
    123         CloseHandle (m_obj->map_handle);
    124     if (m_obj->file_handle != INVALID_HANDLE_VALUE)
    125         CloseHandle (m_obj->file_handle);
    126     if (m_obj->tagname)
    127         PyMem_Free(m_obj->tagname);
    128 #endif /* MS_WINDOWS */
    129 
    130 #ifdef UNIX
    131     if (m_obj->fd >= 0)
    132         (void) close(m_obj->fd);
    133     if (m_obj->data!=NULL) {
    134         if (m_obj->access != ACCESS_READ && m_obj->access != ACCESS_COPY)
    135             msync(m_obj->data, m_obj->size, MS_SYNC);
    136         munmap(m_obj->data, m_obj->size);
    137     }
    138 #endif /* UNIX */
    139 
    140     Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
    141 }
    142 
    143 static PyObject *
    144 mmap_close_method(mmap_object *self, PyObject *unused)
    145 {
    146 #ifdef MS_WINDOWS
    147     /* For each resource we maintain, we need to check
    148        the value is valid, and if so, free the resource
    149        and set the member value to an invalid value so
    150        the dealloc does not attempt to resource clearing
    151        again.
    152        TODO - should we check for errors in the close operations???
    153     */
    154     if (self->data != NULL) {
    155         UnmapViewOfFile(self->data);
    156         self->data = NULL;
    157     }
    158     if (self->map_handle != NULL) {
    159         CloseHandle(self->map_handle);
    160         self->map_handle = NULL;
    161     }
    162     if (self->file_handle != INVALID_HANDLE_VALUE) {
    163         CloseHandle(self->file_handle);
    164         self->file_handle = INVALID_HANDLE_VALUE;
    165     }
    166 #endif /* MS_WINDOWS */
    167 
    168 #ifdef UNIX
    169     if (0 <= self->fd)
    170         (void) close(self->fd);
    171     self->fd = -1;
    172     if (self->data != NULL) {
    173         munmap(self->data, self->size);
    174         self->data = NULL;
    175     }
    176 #endif
    177 
    178     Py_INCREF(Py_None);
    179     return Py_None;
    180 }
    181 
    182 #ifdef MS_WINDOWS
    183 #define CHECK_VALID(err)                                                \
    184 do {                                                                    \
    185     if (self->map_handle == NULL) {                                     \
    186     PyErr_SetString(PyExc_ValueError, "mmap closed or invalid");        \
    187     return err;                                                         \
    188     }                                                                   \
    189 } while (0)
    190 #endif /* MS_WINDOWS */
    191 
    192 #ifdef UNIX
    193 #define CHECK_VALID(err)                                                \
    194 do {                                                                    \
    195     if (self->data == NULL) {                                           \
    196     PyErr_SetString(PyExc_ValueError, "mmap closed or invalid");        \
    197     return err;                                                         \
    198     }                                                                   \
    199 } while (0)
    200 #endif /* UNIX */
    201 
    202 static PyObject *
    203 mmap_read_byte_method(mmap_object *self,
    204                       PyObject *unused)
    205 {
    206     CHECK_VALID(NULL);
    207     if (self->pos >= self->size) {
    208         PyErr_SetString(PyExc_ValueError, "read byte out of range");
    209         return NULL;
    210     }
    211     return PyString_FromStringAndSize(&self->data[self->pos++], 1);
    212 }
    213 
    214 static PyObject *
    215 mmap_read_line_method(mmap_object *self,
    216                       PyObject *unused)
    217 {
    218     Py_ssize_t remaining;
    219     char *start, *eol;
    220     PyObject *result;
    221 
    222     CHECK_VALID(NULL);
    223 
    224     remaining = (self->pos < self->size) ? self->size - self->pos : 0;
    225     if (!remaining)
    226         return PyString_FromString("");
    227     start = self->data + self->pos;
    228     eol = memchr(start, '\n', remaining);
    229     if (!eol)
    230         eol = self->data + self->size;
    231     else
    232         ++eol; /* advance past newline */
    233     result = PyString_FromStringAndSize(start, (eol - start));
    234     self->pos += (eol - start);
    235     return result;
    236 }
    237 
    238 static PyObject *
    239 mmap_read_method(mmap_object *self,
    240                  PyObject *args)
    241 {
    242     Py_ssize_t num_bytes, remaining;
    243     PyObject *result;
    244 
    245     CHECK_VALID(NULL);
    246     if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
    247         return NULL;
    248 
    249     /* silently 'adjust' out-of-range requests */
    250     remaining = (self->pos < self->size) ? self->size - self->pos : 0;
    251     if (num_bytes < 0 || num_bytes > remaining)
    252         num_bytes = remaining;
    253     result = PyString_FromStringAndSize(&self->data[self->pos], num_bytes);
    254     self->pos += num_bytes;
    255     return result;
    256 }
    257 
    258 static PyObject *
    259 mmap_gfind(mmap_object *self,
    260            PyObject *args,
    261            int reverse)
    262 {
    263     Py_ssize_t start = self->pos;
    264     Py_ssize_t end = self->size;
    265     const char *needle;
    266     Py_ssize_t len;
    267 
    268     CHECK_VALID(NULL);
    269     if (!PyArg_ParseTuple(args, reverse ? "s#|nn:rfind" : "s#|nn:find",
    270                           &needle, &len, &start, &end)) {
    271         return NULL;
    272     } else {
    273         const char *p, *start_p, *end_p;
    274         int sign = reverse ? -1 : 1;
    275 
    276         if (start < 0)
    277             start += self->size;
    278         if (start < 0)
    279             start = 0;
    280         else if (start > self->size)
    281             start = self->size;
    282 
    283         if (end < 0)
    284             end += self->size;
    285         if (end < 0)
    286             end = 0;
    287         else if (end > self->size)
    288             end = self->size;
    289 
    290         start_p = self->data + start;
    291         end_p = self->data + end;
    292 
    293         for (p = (reverse ? end_p - len : start_p);
    294              (p >= start_p) && (p + len <= end_p); p += sign) {
    295             Py_ssize_t i;
    296             for (i = 0; i < len && needle[i] == p[i]; ++i)
    297                 /* nothing */;
    298             if (i == len) {
    299                 return PyInt_FromSsize_t(p - self->data);
    300             }
    301         }
    302         return PyInt_FromLong(-1);
    303     }
    304 }
    305 
    306 static PyObject *
    307 mmap_find_method(mmap_object *self,
    308                  PyObject *args)
    309 {
    310     return mmap_gfind(self, args, 0);
    311 }
    312 
    313 static PyObject *
    314 mmap_rfind_method(mmap_object *self,
    315                  PyObject *args)
    316 {
    317     return mmap_gfind(self, args, 1);
    318 }
    319 
    320 static int
    321 is_writeable(mmap_object *self)
    322 {
    323     if (self->access != ACCESS_READ)
    324         return 1;
    325     PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
    326     return 0;
    327 }
    328 
    329 static int
    330 is_resizeable(mmap_object *self)
    331 {
    332     if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
    333         return 1;
    334     PyErr_Format(PyExc_TypeError,
    335                  "mmap can't resize a readonly or copy-on-write memory map.");
    336     return 0;
    337 }
    338 
    339 
    340 static PyObject *
    341 mmap_write_method(mmap_object *self,
    342                   PyObject *args)
    343 {
    344     Py_ssize_t length;
    345     char *data;
    346 
    347     CHECK_VALID(NULL);
    348     if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
    349         return(NULL);
    350 
    351     if (!is_writeable(self))
    352         return NULL;
    353 
    354     if (self->pos > self->size || self->size - self->pos < length) {
    355         PyErr_SetString(PyExc_ValueError, "data out of range");
    356         return NULL;
    357     }
    358     memcpy(&self->data[self->pos], data, length);
    359     self->pos += length;
    360     Py_INCREF(Py_None);
    361     return Py_None;
    362 }
    363 
    364 static PyObject *
    365 mmap_write_byte_method(mmap_object *self,
    366                        PyObject *args)
    367 {
    368     char value;
    369 
    370     CHECK_VALID(NULL);
    371     if (!PyArg_ParseTuple(args, "c:write_byte", &value))
    372         return(NULL);
    373 
    374     if (!is_writeable(self))
    375         return NULL;
    376 
    377     if (self->pos < self->size) {
    378         self->data[self->pos++] = value;
    379         Py_INCREF(Py_None);
    380         return Py_None;
    381     }
    382     else {
    383         PyErr_SetString(PyExc_ValueError, "write byte out of range");
    384         return NULL;
    385     }
    386 }
    387 
    388 static PyObject *
    389 mmap_size_method(mmap_object *self,
    390                  PyObject *unused)
    391 {
    392     CHECK_VALID(NULL);
    393 
    394 #ifdef MS_WINDOWS
    395     if (self->file_handle != INVALID_HANDLE_VALUE) {
    396         DWORD low,high;
    397         PY_LONG_LONG size;
    398         low = GetFileSize(self->file_handle, &high);
    399         if (low == INVALID_FILE_SIZE) {
    400             /* It might be that the function appears to have failed,
    401                when indeed its size equals INVALID_FILE_SIZE */
    402             DWORD error = GetLastError();
    403             if (error != NO_ERROR)
    404                 return PyErr_SetFromWindowsErr(error);
    405         }
    406         if (!high && low < LONG_MAX)
    407             return PyInt_FromLong((long)low);
    408         size = (((PY_LONG_LONG)high)<<32) + low;
    409         return PyLong_FromLongLong(size);
    410     } else {
    411         return PyInt_FromSsize_t(self->size);
    412     }
    413 #endif /* MS_WINDOWS */
    414 
    415 #ifdef UNIX
    416     {
    417         struct stat buf;
    418         if (-1 == fstat(self->fd, &buf)) {
    419             PyErr_SetFromErrno(mmap_module_error);
    420             return NULL;
    421         }
    422 #ifdef HAVE_LARGEFILE_SUPPORT
    423         return PyLong_FromLongLong(buf.st_size);
    424 #else
    425         return PyInt_FromLong(buf.st_size);
    426 #endif
    427     }
    428 #endif /* UNIX */
    429 }
    430 
    431 /* This assumes that you want the entire file mapped,
    432  / and when recreating the map will make the new file
    433  / have the new size
    434  /
    435  / Is this really necessary?  This could easily be done
    436  / from python by just closing and re-opening with the
    437  / new size?
    438  */
    439 
    440 static PyObject *
    441 mmap_resize_method(mmap_object *self,
    442                    PyObject *args)
    443 {
    444     Py_ssize_t new_size;
    445     CHECK_VALID(NULL);
    446     if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
    447         !is_resizeable(self)) {
    448         return NULL;
    449     }
    450     if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) {
    451         PyErr_SetString(PyExc_ValueError, "new size out of range");
    452         return NULL;
    453     }
    454 
    455     {
    456 #ifdef MS_WINDOWS
    457         DWORD dwErrCode = 0;
    458         DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
    459         /* First, unmap the file view */
    460         UnmapViewOfFile(self->data);
    461         self->data = NULL;
    462         /* Close the mapping object */
    463         CloseHandle(self->map_handle);
    464         self->map_handle = NULL;
    465         /* Move to the desired EOF position */
    466         newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
    467         newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
    468         off_hi = (DWORD)(self->offset >> 32);
    469         off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
    470         SetFilePointer(self->file_handle,
    471                        newSizeLow, &newSizeHigh, FILE_BEGIN);
    472         /* Change the size of the file */
    473         SetEndOfFile(self->file_handle);
    474         /* Create another mapping object and remap the file view */
    475         self->map_handle = CreateFileMapping(
    476             self->file_handle,
    477             NULL,
    478             PAGE_READWRITE,
    479             0,
    480             0,
    481             self->tagname);
    482         if (self->map_handle != NULL) {
    483             self->data = (char *) MapViewOfFile(self->map_handle,
    484                                                 FILE_MAP_WRITE,
    485                                                 off_hi,
    486                                                 off_lo,
    487                                                 new_size);
    488             if (self->data != NULL) {
    489                 self->size = new_size;
    490                 Py_INCREF(Py_None);
    491                 return Py_None;
    492             } else {
    493                 dwErrCode = GetLastError();
    494                 CloseHandle(self->map_handle);
    495                 self->map_handle = NULL;
    496             }
    497         } else {
    498             dwErrCode = GetLastError();
    499         }
    500         PyErr_SetFromWindowsErr(dwErrCode);
    501         return NULL;
    502 #endif /* MS_WINDOWS */
    503 
    504 #ifdef UNIX
    505 #ifndef HAVE_MREMAP
    506         PyErr_SetString(PyExc_SystemError,
    507                         "mmap: resizing not available--no mremap()");
    508         return NULL;
    509 #else
    510         void *newmap;
    511 
    512         if (self->fd != -1 && ftruncate(self->fd, self->offset + new_size) == -1) {
    513             PyErr_SetFromErrno(mmap_module_error);
    514             return NULL;
    515         }
    516 
    517 #ifdef MREMAP_MAYMOVE
    518         newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
    519 #else
    520 #if defined(__NetBSD__)
    521         newmap = mremap(self->data, self->size, self->data, new_size, 0);
    522 #else
    523         newmap = mremap(self->data, self->size, new_size, 0);
    524 #endif /* __NetBSD__ */
    525 #endif
    526         if (newmap == (void *)-1)
    527         {
    528             PyErr_SetFromErrno(mmap_module_error);
    529             return NULL;
    530         }
    531         self->data = newmap;
    532         self->size = new_size;
    533         Py_INCREF(Py_None);
    534         return Py_None;
    535 #endif /* HAVE_MREMAP */
    536 #endif /* UNIX */
    537     }
    538 }
    539 
    540 static PyObject *
    541 mmap_tell_method(mmap_object *self, PyObject *unused)
    542 {
    543     CHECK_VALID(NULL);
    544     return PyInt_FromSize_t(self->pos);
    545 }
    546 
    547 static PyObject *
    548 mmap_flush_method(mmap_object *self, PyObject *args)
    549 {
    550     Py_ssize_t offset = 0;
    551     Py_ssize_t size = self->size;
    552     CHECK_VALID(NULL);
    553     if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
    554         return NULL;
    555     if (size < 0 || offset < 0 || self->size - offset < size) {
    556         PyErr_SetString(PyExc_ValueError, "flush values out of range");
    557         return NULL;
    558     }
    559 
    560     if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
    561         return PyLong_FromLong(0);
    562 
    563 #ifdef MS_WINDOWS
    564     return PyInt_FromLong((long) FlushViewOfFile(self->data+offset, size));
    565 #elif defined(UNIX)
    566     /* XXX semantics of return value? */
    567     /* XXX flags for msync? */
    568     if (-1 == msync(self->data + offset, size, MS_SYNC)) {
    569         PyErr_SetFromErrno(mmap_module_error);
    570         return NULL;
    571     }
    572     return PyInt_FromLong(0);
    573 #else
    574     PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
    575     return NULL;
    576 #endif
    577 }
    578 
    579 static PyObject *
    580 mmap_seek_method(mmap_object *self, PyObject *args)
    581 {
    582     Py_ssize_t dist;
    583     int how=0;
    584     CHECK_VALID(NULL);
    585     if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
    586         return NULL;
    587     else {
    588         Py_ssize_t where;
    589         switch (how) {
    590         case 0: /* relative to start */
    591             where = dist;
    592             break;
    593         case 1: /* relative to current position */
    594             if (PY_SSIZE_T_MAX - self->pos < dist)
    595                 goto onoutofrange;
    596             where = self->pos + dist;
    597             break;
    598         case 2: /* relative to end */
    599             if (PY_SSIZE_T_MAX - self->size < dist)
    600                 goto onoutofrange;
    601             where = self->size + dist;
    602             break;
    603         default:
    604             PyErr_SetString(PyExc_ValueError, "unknown seek type");
    605             return NULL;
    606         }
    607         if (where > self->size || where < 0)
    608             goto onoutofrange;
    609         self->pos = where;
    610         Py_INCREF(Py_None);
    611         return Py_None;
    612     }
    613 
    614   onoutofrange:
    615     PyErr_SetString(PyExc_ValueError, "seek out of range");
    616     return NULL;
    617 }
    618 
    619 static PyObject *
    620 mmap_move_method(mmap_object *self, PyObject *args)
    621 {
    622     Py_ssize_t dest, src, cnt;
    623     CHECK_VALID(NULL);
    624     if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) ||
    625         !is_writeable(self)) {
    626         return NULL;
    627     } else {
    628         /* bounds check the values */
    629         if (dest < 0 || src < 0 || cnt < 0)
    630             goto bounds;
    631         if (self->size - dest < cnt || self->size - src < cnt)
    632             goto bounds;
    633 
    634         memmove(&self->data[dest], &self->data[src], cnt);
    635 
    636         Py_INCREF(Py_None);
    637         return Py_None;
    638 
    639       bounds:
    640         PyErr_SetString(PyExc_ValueError,
    641                         "source, destination, or count out of range");
    642         return NULL;
    643     }
    644 }
    645 
    646 #ifdef MS_WINDOWS
    647 static PyObject *
    648 mmap__sizeof__method(mmap_object *self, void *unused)
    649 {
    650     Py_ssize_t res;
    651 
    652     res = _PyObject_SIZE(Py_TYPE(self));
    653     if (self->tagname)
    654         res += strlen(self->tagname) + 1;
    655     return PyLong_FromSsize_t(res);
    656 }
    657 #endif
    658 
    659 static struct PyMethodDef mmap_object_methods[] = {
    660     {"close",           (PyCFunction) mmap_close_method,        METH_NOARGS},
    661     {"find",            (PyCFunction) mmap_find_method,         METH_VARARGS},
    662     {"rfind",           (PyCFunction) mmap_rfind_method,        METH_VARARGS},
    663     {"flush",           (PyCFunction) mmap_flush_method,        METH_VARARGS},
    664     {"move",            (PyCFunction) mmap_move_method,         METH_VARARGS},
    665     {"read",            (PyCFunction) mmap_read_method,         METH_VARARGS},
    666     {"read_byte",       (PyCFunction) mmap_read_byte_method,    METH_NOARGS},
    667     {"readline",        (PyCFunction) mmap_read_line_method,    METH_NOARGS},
    668     {"resize",          (PyCFunction) mmap_resize_method,       METH_VARARGS},
    669     {"seek",            (PyCFunction) mmap_seek_method,         METH_VARARGS},
    670     {"size",            (PyCFunction) mmap_size_method,         METH_NOARGS},
    671     {"tell",            (PyCFunction) mmap_tell_method,         METH_NOARGS},
    672     {"write",           (PyCFunction) mmap_write_method,        METH_VARARGS},
    673     {"write_byte",      (PyCFunction) mmap_write_byte_method,   METH_VARARGS},
    674 #ifdef MS_WINDOWS
    675     {"__sizeof__",      (PyCFunction) mmap__sizeof__method,     METH_NOARGS},
    676 #endif
    677     {NULL,         NULL}       /* sentinel */
    678 };
    679 
    680 /* Functions for treating an mmap'ed file as a buffer */
    681 
    682 static Py_ssize_t
    683 mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
    684 {
    685     CHECK_VALID(-1);
    686     if (index != 0) {
    687         PyErr_SetString(PyExc_SystemError,
    688                         "Accessing non-existent mmap segment");
    689         return -1;
    690     }
    691     *ptr = self->data;
    692     return self->size;
    693 }
    694 
    695 static Py_ssize_t
    696 mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
    697 {
    698     CHECK_VALID(-1);
    699     if (index != 0) {
    700         PyErr_SetString(PyExc_SystemError,
    701                         "Accessing non-existent mmap segment");
    702         return -1;
    703     }
    704     if (!is_writeable(self))
    705         return -1;
    706     *ptr = self->data;
    707     return self->size;
    708 }
    709 
    710 static Py_ssize_t
    711 mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
    712 {
    713     CHECK_VALID(-1);
    714     if (lenp)
    715         *lenp = self->size;
    716     return 1;
    717 }
    718 
    719 static Py_ssize_t
    720 mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
    721 {
    722     if (index != 0) {
    723         PyErr_SetString(PyExc_SystemError,
    724                         "accessing non-existent buffer segment");
    725         return -1;
    726     }
    727     *ptr = (const char *)self->data;
    728     return self->size;
    729 }
    730 
    731 static Py_ssize_t
    732 mmap_length(mmap_object *self)
    733 {
    734     CHECK_VALID(-1);
    735     return self->size;
    736 }
    737 
    738 static PyObject *
    739 mmap_item(mmap_object *self, Py_ssize_t i)
    740 {
    741     CHECK_VALID(NULL);
    742     if (i < 0 || i >= self->size) {
    743         PyErr_SetString(PyExc_IndexError, "mmap index out of range");
    744         return NULL;
    745     }
    746     return PyString_FromStringAndSize(self->data + i, 1);
    747 }
    748 
    749 static PyObject *
    750 mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
    751 {
    752     CHECK_VALID(NULL);
    753     if (ilow < 0)
    754         ilow = 0;
    755     else if (ilow > self->size)
    756         ilow = self->size;
    757     if (ihigh < 0)
    758         ihigh = 0;
    759     if (ihigh < ilow)
    760         ihigh = ilow;
    761     else if (ihigh > self->size)
    762         ihigh = self->size;
    763 
    764     return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
    765 }
    766 
    767 static PyObject *
    768 mmap_subscript(mmap_object *self, PyObject *item)
    769 {
    770     CHECK_VALID(NULL);
    771     if (PyIndex_Check(item)) {
    772         Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
    773         if (i == -1 && PyErr_Occurred())
    774             return NULL;
    775         if (i < 0)
    776             i += self->size;
    777         if (i < 0 || i >= self->size) {
    778             PyErr_SetString(PyExc_IndexError,
    779                 "mmap index out of range");
    780             return NULL;
    781         }
    782         return PyString_FromStringAndSize(self->data + i, 1);
    783     }
    784     else if (PySlice_Check(item)) {
    785         Py_ssize_t start, stop, step, slicelen;
    786 
    787         if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
    788                          &start, &stop, &step, &slicelen) < 0) {
    789             return NULL;
    790         }
    791 
    792         if (slicelen <= 0)
    793             return PyString_FromStringAndSize("", 0);
    794         else if (step == 1)
    795             return PyString_FromStringAndSize(self->data + start,
    796                                               slicelen);
    797         else {
    798             char *result_buf = (char *)PyMem_Malloc(slicelen);
    799             Py_ssize_t cur, i;
    800             PyObject *result;
    801 
    802             if (result_buf == NULL)
    803                 return PyErr_NoMemory();
    804             for (cur = start, i = 0; i < slicelen;
    805                  cur += step, i++) {
    806                 result_buf[i] = self->data[cur];
    807             }
    808             result = PyString_FromStringAndSize(result_buf,
    809                                                 slicelen);
    810             PyMem_Free(result_buf);
    811             return result;
    812         }
    813     }
    814     else {
    815         PyErr_SetString(PyExc_TypeError,
    816                         "mmap indices must be integers");
    817         return NULL;
    818     }
    819 }
    820 
    821 static PyObject *
    822 mmap_concat(mmap_object *self, PyObject *bb)
    823 {
    824     CHECK_VALID(NULL);
    825     PyErr_SetString(PyExc_SystemError,
    826                     "mmaps don't support concatenation");
    827     return NULL;
    828 }
    829 
    830 static PyObject *
    831 mmap_repeat(mmap_object *self, Py_ssize_t n)
    832 {
    833     CHECK_VALID(NULL);
    834     PyErr_SetString(PyExc_SystemError,
    835                     "mmaps don't support repeat operation");
    836     return NULL;
    837 }
    838 
    839 static int
    840 mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
    841 {
    842     const char *buf;
    843 
    844     CHECK_VALID(-1);
    845     if (ilow < 0)
    846         ilow = 0;
    847     else if (ilow > self->size)
    848         ilow = self->size;
    849     if (ihigh < 0)
    850         ihigh = 0;
    851     if (ihigh < ilow)
    852         ihigh = ilow;
    853     else if (ihigh > self->size)
    854         ihigh = self->size;
    855 
    856     if (v == NULL) {
    857         PyErr_SetString(PyExc_TypeError,
    858                         "mmap object doesn't support slice deletion");
    859         return -1;
    860     }
    861     if (! (PyString_Check(v)) ) {
    862         PyErr_SetString(PyExc_IndexError,
    863                         "mmap slice assignment must be a string");
    864         return -1;
    865     }
    866     if (PyString_Size(v) != (ihigh - ilow)) {
    867         PyErr_SetString(PyExc_IndexError,
    868                         "mmap slice assignment is wrong size");
    869         return -1;
    870     }
    871     if (!is_writeable(self))
    872         return -1;
    873     buf = PyString_AsString(v);
    874     memcpy(self->data + ilow, buf, ihigh-ilow);
    875     return 0;
    876 }
    877 
    878 static int
    879 mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
    880 {
    881     const char *buf;
    882 
    883     CHECK_VALID(-1);
    884     if (i < 0 || i >= self->size) {
    885         PyErr_SetString(PyExc_IndexError, "mmap index out of range");
    886         return -1;
    887     }
    888     if (v == NULL) {
    889         PyErr_SetString(PyExc_TypeError,
    890                         "mmap object doesn't support item deletion");
    891         return -1;
    892     }
    893     if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
    894         PyErr_SetString(PyExc_IndexError,
    895                         "mmap assignment must be single-character string");
    896         return -1;
    897     }
    898     if (!is_writeable(self))
    899         return -1;
    900     buf = PyString_AsString(v);
    901     self->data[i] = buf[0];
    902     return 0;
    903 }
    904 
    905 static int
    906 mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
    907 {
    908     CHECK_VALID(-1);
    909 
    910     if (PyIndex_Check(item)) {
    911         Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
    912         const char *buf;
    913 
    914         if (i == -1 && PyErr_Occurred())
    915             return -1;
    916         if (i < 0)
    917             i += self->size;
    918         if (i < 0 || i >= self->size) {
    919             PyErr_SetString(PyExc_IndexError,
    920                 "mmap index out of range");
    921             return -1;
    922         }
    923         if (value == NULL) {
    924             PyErr_SetString(PyExc_TypeError,
    925                 "mmap object doesn't support item deletion");
    926             return -1;
    927         }
    928         if (!PyString_Check(value) || PyString_Size(value) != 1) {
    929             PyErr_SetString(PyExc_IndexError,
    930               "mmap assignment must be single-character string");
    931             return -1;
    932         }
    933         if (!is_writeable(self))
    934             return -1;
    935         buf = PyString_AsString(value);
    936         self->data[i] = buf[0];
    937         return 0;
    938     }
    939     else if (PySlice_Check(item)) {
    940         Py_ssize_t start, stop, step, slicelen;
    941 
    942         if (PySlice_GetIndicesEx((PySliceObject *)item,
    943                                  self->size, &start, &stop,
    944                                  &step, &slicelen) < 0) {
    945             return -1;
    946         }
    947         if (value == NULL) {
    948             PyErr_SetString(PyExc_TypeError,
    949                 "mmap object doesn't support slice deletion");
    950             return -1;
    951         }
    952         if (!PyString_Check(value)) {
    953             PyErr_SetString(PyExc_IndexError,
    954                 "mmap slice assignment must be a string");
    955             return -1;
    956         }
    957         if (PyString_Size(value) != slicelen) {
    958             PyErr_SetString(PyExc_IndexError,
    959                 "mmap slice assignment is wrong size");
    960             return -1;
    961         }
    962         if (!is_writeable(self))
    963             return -1;
    964 
    965         if (slicelen == 0)
    966             return 0;
    967         else if (step == 1) {
    968             const char *buf = PyString_AsString(value);
    969 
    970             if (buf == NULL)
    971                 return -1;
    972             memcpy(self->data + start, buf, slicelen);
    973             return 0;
    974         }
    975         else {
    976             Py_ssize_t cur, i;
    977             const char *buf = PyString_AsString(value);
    978 
    979             if (buf == NULL)
    980                 return -1;
    981             for (cur = start, i = 0; i < slicelen;
    982                  cur += step, i++) {
    983                 self->data[cur] = buf[i];
    984             }
    985             return 0;
    986         }
    987     }
    988     else {
    989         PyErr_SetString(PyExc_TypeError,
    990                         "mmap indices must be integer");
    991         return -1;
    992     }
    993 }
    994 
    995 static PySequenceMethods mmap_as_sequence = {
    996     (lenfunc)mmap_length,                      /*sq_length*/
    997     (binaryfunc)mmap_concat,                   /*sq_concat*/
    998     (ssizeargfunc)mmap_repeat,                 /*sq_repeat*/
    999     (ssizeargfunc)mmap_item,                           /*sq_item*/
   1000     (ssizessizeargfunc)mmap_slice,             /*sq_slice*/
   1001     (ssizeobjargproc)mmap_ass_item,            /*sq_ass_item*/
   1002     (ssizessizeobjargproc)mmap_ass_slice,      /*sq_ass_slice*/
   1003 };
   1004 
   1005 static PyMappingMethods mmap_as_mapping = {
   1006     (lenfunc)mmap_length,
   1007     (binaryfunc)mmap_subscript,
   1008     (objobjargproc)mmap_ass_subscript,
   1009 };
   1010 
   1011 static PyBufferProcs mmap_as_buffer = {
   1012     (readbufferproc)mmap_buffer_getreadbuf,
   1013     (writebufferproc)mmap_buffer_getwritebuf,
   1014     (segcountproc)mmap_buffer_getsegcount,
   1015     (charbufferproc)mmap_buffer_getcharbuffer,
   1016 };
   1017 
   1018 static PyObject *
   1019 new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
   1020 
   1021 PyDoc_STRVAR(mmap_doc,
   1022 "Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
   1023 \n\
   1024 Maps length bytes from the file specified by the file handle fileno,\n\
   1025 and returns a mmap object.  If length is larger than the current size\n\
   1026 of the file, the file is extended to contain length bytes.  If length\n\
   1027 is 0, the maximum length of the map is the current size of the file,\n\
   1028 except that if the file is empty Windows raises an exception (you cannot\n\
   1029 create an empty mapping on Windows).\n\
   1030 \n\
   1031 Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
   1032 \n\
   1033 Maps length bytes from the file specified by the file descriptor fileno,\n\
   1034 and returns a mmap object.  If length is 0, the maximum length of the map\n\
   1035 will be the current size of the file when mmap is called.\n\
   1036 flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
   1037 private copy-on-write mapping, so changes to the contents of the mmap\n\
   1038 object will be private to this process, and MAP_SHARED creates a mapping\n\
   1039 that's shared with all other processes mapping the same areas of the file.\n\
   1040 The default value is MAP_SHARED.\n\
   1041 \n\
   1042 To map anonymous memory, pass -1 as the fileno (both versions).");
   1043 
   1044 
   1045 static PyTypeObject mmap_object_type = {
   1046     PyVarObject_HEAD_INIT(NULL, 0)
   1047     "mmap.mmap",                                /* tp_name */
   1048     sizeof(mmap_object),                        /* tp_size */
   1049     0,                                          /* tp_itemsize */
   1050     /* methods */
   1051     (destructor) mmap_object_dealloc,           /* tp_dealloc */
   1052     0,                                          /* tp_print */
   1053     0,                                          /* tp_getattr */
   1054     0,                                          /* tp_setattr */
   1055     0,                                          /* tp_compare */
   1056     0,                                          /* tp_repr */
   1057     0,                                          /* tp_as_number */
   1058     &mmap_as_sequence,                          /*tp_as_sequence*/
   1059     &mmap_as_mapping,                           /*tp_as_mapping*/
   1060     0,                                          /*tp_hash*/
   1061     0,                                          /*tp_call*/
   1062     0,                                          /*tp_str*/
   1063     PyObject_GenericGetAttr,                    /*tp_getattro*/
   1064     0,                                          /*tp_setattro*/
   1065     &mmap_as_buffer,                            /*tp_as_buffer*/
   1066     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GETCHARBUFFER,                   /*tp_flags*/
   1067     mmap_doc,                                   /*tp_doc*/
   1068     0,                                          /* tp_traverse */
   1069     0,                                          /* tp_clear */
   1070     0,                                          /* tp_richcompare */
   1071     0,                                          /* tp_weaklistoffset */
   1072     0,                                          /* tp_iter */
   1073     0,                                          /* tp_iternext */
   1074     mmap_object_methods,                        /* tp_methods */
   1075     0,                                          /* tp_members */
   1076     0,                                          /* tp_getset */
   1077     0,                                          /* tp_base */
   1078     0,                                          /* tp_dict */
   1079     0,                                          /* tp_descr_get */
   1080     0,                                          /* tp_descr_set */
   1081     0,                                          /* tp_dictoffset */
   1082     0,                                      /* tp_init */
   1083     PyType_GenericAlloc,                        /* tp_alloc */
   1084     new_mmap_object,                            /* tp_new */
   1085     PyObject_Del,                           /* tp_free */
   1086 };
   1087 
   1088 
   1089 #ifdef UNIX
   1090 #ifdef HAVE_LARGEFILE_SUPPORT
   1091 #define _Py_PARSE_OFF_T "L"
   1092 #else
   1093 #define _Py_PARSE_OFF_T "l"
   1094 #endif
   1095 
   1096 static PyObject *
   1097 new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
   1098 {
   1099 #ifdef HAVE_FSTAT
   1100     struct stat st;
   1101 #endif
   1102     mmap_object *m_obj;
   1103     Py_ssize_t map_size;
   1104     off_t offset = 0;
   1105     int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
   1106     int devzero = -1;
   1107     int access = (int)ACCESS_DEFAULT;
   1108     static char *keywords[] = {"fileno", "length",
   1109                                      "flags", "prot",
   1110                                      "access", "offset", NULL};
   1111 
   1112     if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|iii" _Py_PARSE_OFF_T, keywords,
   1113                                      &fd, &map_size, &flags, &prot,
   1114                                      &access, &offset))
   1115         return NULL;
   1116     if (map_size < 0) {
   1117         PyErr_SetString(PyExc_OverflowError,
   1118                         "memory mapped length must be postiive");
   1119         return NULL;
   1120     }
   1121     if (offset < 0) {
   1122         PyErr_SetString(PyExc_OverflowError,
   1123             "memory mapped offset must be positive");
   1124         return NULL;
   1125     }
   1126 
   1127     if ((access != (int)ACCESS_DEFAULT) &&
   1128         ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
   1129         return PyErr_Format(PyExc_ValueError,
   1130                             "mmap can't specify both access and flags, prot.");
   1131     switch ((access_mode)access) {
   1132     case ACCESS_READ:
   1133         flags = MAP_SHARED;
   1134         prot = PROT_READ;
   1135         break;
   1136     case ACCESS_WRITE:
   1137         flags = MAP_SHARED;
   1138         prot = PROT_READ | PROT_WRITE;
   1139         break;
   1140     case ACCESS_COPY:
   1141         flags = MAP_PRIVATE;
   1142         prot = PROT_READ | PROT_WRITE;
   1143         break;
   1144     case ACCESS_DEFAULT:
   1145         /* map prot to access type */
   1146         if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
   1147             /* ACCESS_DEFAULT */
   1148         }
   1149         else if (prot & PROT_WRITE) {
   1150             access = ACCESS_WRITE;
   1151         }
   1152         else {
   1153             access = ACCESS_READ;
   1154         }
   1155         break;
   1156     default:
   1157         return PyErr_Format(PyExc_ValueError,
   1158                             "mmap invalid access parameter.");
   1159     }
   1160 
   1161 #ifdef __APPLE__
   1162     /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
   1163        fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
   1164     if (fd != -1)
   1165         (void)fcntl(fd, F_FULLFSYNC);
   1166 #endif
   1167 #ifdef HAVE_FSTAT
   1168 #  ifdef __VMS
   1169     /* on OpenVMS we must ensure that all bytes are written to the file */
   1170     if (fd != -1) {
   1171         fsync(fd);
   1172     }
   1173 #  endif
   1174     if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
   1175         if (map_size == 0) {
   1176             if (st.st_size == 0) {
   1177                 PyErr_SetString(PyExc_ValueError,
   1178                                 "cannot mmap an empty file");
   1179                 return NULL;
   1180             }
   1181             if (offset >= st.st_size) {
   1182                 PyErr_SetString(PyExc_ValueError,
   1183                                 "mmap offset is greater than file size");
   1184                 return NULL;
   1185             }
   1186             if (st.st_size - offset > PY_SSIZE_T_MAX) {
   1187                 PyErr_SetString(PyExc_ValueError,
   1188                                  "mmap length is too large");
   1189                 return NULL;
   1190             }
   1191             map_size = (Py_ssize_t) (st.st_size - offset);
   1192         } else if (offset > st.st_size || st.st_size - offset < map_size) {
   1193             PyErr_SetString(PyExc_ValueError,
   1194                             "mmap length is greater than file size");
   1195             return NULL;
   1196         }
   1197     }
   1198 #endif
   1199     m_obj = (mmap_object *)type->tp_alloc(type, 0);
   1200     if (m_obj == NULL) {return NULL;}
   1201     m_obj->data = NULL;
   1202     m_obj->size = map_size;
   1203     m_obj->pos = 0;
   1204     m_obj->offset = offset;
   1205     if (fd == -1) {
   1206         m_obj->fd = -1;
   1207         /* Assume the caller wants to map anonymous memory.
   1208            This is the same behaviour as Windows.  mmap.mmap(-1, size)
   1209            on both Windows and Unix map anonymous memory.
   1210         */
   1211 #ifdef MAP_ANONYMOUS
   1212         /* BSD way to map anonymous memory */
   1213         flags |= MAP_ANONYMOUS;
   1214 #else
   1215         /* SVR4 method to map anonymous memory is to open /dev/zero */
   1216         fd = devzero = open("/dev/zero", O_RDWR);
   1217         if (devzero == -1) {
   1218             Py_DECREF(m_obj);
   1219             PyErr_SetFromErrno(mmap_module_error);
   1220             return NULL;
   1221         }
   1222 #endif
   1223     } else {
   1224         m_obj->fd = dup(fd);
   1225         if (m_obj->fd == -1) {
   1226             Py_DECREF(m_obj);
   1227             PyErr_SetFromErrno(mmap_module_error);
   1228             return NULL;
   1229         }
   1230     }
   1231 
   1232     m_obj->data = mmap(NULL, map_size,
   1233                        prot, flags,
   1234                        fd, offset);
   1235 
   1236     if (devzero != -1) {
   1237         close(devzero);
   1238     }
   1239 
   1240     if (m_obj->data == (char *)-1) {
   1241         m_obj->data = NULL;
   1242         Py_DECREF(m_obj);
   1243         PyErr_SetFromErrno(mmap_module_error);
   1244         return NULL;
   1245     }
   1246     m_obj->access = (access_mode)access;
   1247     return (PyObject *)m_obj;
   1248 }
   1249 #endif /* UNIX */
   1250 
   1251 #ifdef MS_WINDOWS
   1252 
   1253 /* A note on sizes and offsets: while the actual map size must hold in a
   1254    Py_ssize_t, both the total file size and the start offset can be longer
   1255    than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
   1256 */
   1257 
   1258 static PyObject *
   1259 new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
   1260 {
   1261     mmap_object *m_obj;
   1262     Py_ssize_t map_size;
   1263     PY_LONG_LONG offset = 0, size;
   1264     DWORD off_hi;       /* upper 32 bits of offset */
   1265     DWORD off_lo;       /* lower 32 bits of offset */
   1266     DWORD size_hi;      /* upper 32 bits of size */
   1267     DWORD size_lo;      /* lower 32 bits of size */
   1268     char *tagname = "";
   1269     DWORD dwErr = 0;
   1270     int fileno;
   1271     HANDLE fh = 0;
   1272     int access = (access_mode)ACCESS_DEFAULT;
   1273     DWORD flProtect, dwDesiredAccess;
   1274     static char *keywords[] = { "fileno", "length",
   1275                                       "tagname",
   1276                                       "access", "offset", NULL };
   1277 
   1278     if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords,
   1279                                      &fileno, &map_size,
   1280                                      &tagname, &access, &offset)) {
   1281         return NULL;
   1282     }
   1283 
   1284     switch((access_mode)access) {
   1285     case ACCESS_READ:
   1286         flProtect = PAGE_READONLY;
   1287         dwDesiredAccess = FILE_MAP_READ;
   1288         break;
   1289     case ACCESS_DEFAULT:  case ACCESS_WRITE:
   1290         flProtect = PAGE_READWRITE;
   1291         dwDesiredAccess = FILE_MAP_WRITE;
   1292         break;
   1293     case ACCESS_COPY:
   1294         flProtect = PAGE_WRITECOPY;
   1295         dwDesiredAccess = FILE_MAP_COPY;
   1296         break;
   1297     default:
   1298         return PyErr_Format(PyExc_ValueError,
   1299                             "mmap invalid access parameter.");
   1300     }
   1301 
   1302     if (map_size < 0) {
   1303         PyErr_SetString(PyExc_OverflowError,
   1304                         "memory mapped length must be postiive");
   1305         return NULL;
   1306     }
   1307     if (offset < 0) {
   1308         PyErr_SetString(PyExc_OverflowError,
   1309             "memory mapped offset must be positive");
   1310         return NULL;
   1311     }
   1312 
   1313     /* assume -1 and 0 both mean invalid filedescriptor
   1314        to 'anonymously' map memory.
   1315        XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
   1316        XXX: Should this code be added?
   1317        if (fileno == 0)
   1318         PyErr_Warn(PyExc_DeprecationWarning,
   1319                    "don't use 0 for anonymous memory");
   1320      */
   1321     if (fileno != -1 && fileno != 0) {
   1322         /* Ensure that fileno is within the CRT's valid range */
   1323         if (_PyVerify_fd(fileno) == 0) {
   1324             PyErr_SetFromErrno(mmap_module_error);
   1325             return NULL;
   1326         }
   1327         fh = (HANDLE)_get_osfhandle(fileno);
   1328         if (fh==(HANDLE)-1) {
   1329             PyErr_SetFromErrno(mmap_module_error);
   1330             return NULL;
   1331         }
   1332         /* Win9x appears to need us seeked to zero */
   1333         lseek(fileno, 0, SEEK_SET);
   1334     }
   1335 
   1336     m_obj = (mmap_object *)type->tp_alloc(type, 0);
   1337     if (m_obj == NULL)
   1338         return NULL;
   1339     /* Set every field to an invalid marker, so we can safely
   1340        destruct the object in the face of failure */
   1341     m_obj->data = NULL;
   1342     m_obj->file_handle = INVALID_HANDLE_VALUE;
   1343     m_obj->map_handle = NULL;
   1344     m_obj->tagname = NULL;
   1345     m_obj->offset = offset;
   1346 
   1347     if (fh) {
   1348         /* It is necessary to duplicate the handle, so the
   1349            Python code can close it on us */
   1350         if (!DuplicateHandle(
   1351             GetCurrentProcess(), /* source process handle */
   1352             fh, /* handle to be duplicated */
   1353             GetCurrentProcess(), /* target proc handle */
   1354             (LPHANDLE)&m_obj->file_handle, /* result */
   1355             0, /* access - ignored due to options value */
   1356             FALSE, /* inherited by child processes? */
   1357             DUPLICATE_SAME_ACCESS)) { /* options */
   1358             dwErr = GetLastError();
   1359             Py_DECREF(m_obj);
   1360             PyErr_SetFromWindowsErr(dwErr);
   1361             return NULL;
   1362         }
   1363         if (!map_size) {
   1364             DWORD low,high;
   1365             low = GetFileSize(fh, &high);
   1366             /* low might just happen to have the value INVALID_FILE_SIZE;
   1367                so we need to check the last error also. */
   1368             if (low == INVALID_FILE_SIZE &&
   1369                 (dwErr = GetLastError()) != NO_ERROR) {
   1370                 Py_DECREF(m_obj);
   1371                 return PyErr_SetFromWindowsErr(dwErr);
   1372             }
   1373 
   1374             size = (((PY_LONG_LONG) high) << 32) + low;
   1375             if (size == 0) {
   1376                 PyErr_SetString(PyExc_ValueError,
   1377                                 "cannot mmap an empty file");
   1378                 Py_DECREF(m_obj);
   1379                 return NULL;
   1380             }
   1381             if (offset >= size) {
   1382                 PyErr_SetString(PyExc_ValueError,
   1383                                 "mmap offset is greater than file size");
   1384                 Py_DECREF(m_obj);
   1385                 return NULL;
   1386             }
   1387             if (size - offset > PY_SSIZE_T_MAX) {
   1388                 PyErr_SetString(PyExc_ValueError,
   1389                                 "mmap length is too large");
   1390                 Py_DECREF(m_obj);
   1391                 return NULL;
   1392             }
   1393             m_obj->size = (Py_ssize_t) (size - offset);
   1394         } else {
   1395             m_obj->size = map_size;
   1396             size = offset + map_size;
   1397         }
   1398     }
   1399     else {
   1400         m_obj->size = map_size;
   1401         size = offset + map_size;
   1402     }
   1403 
   1404     /* set the initial position */
   1405     m_obj->pos = (size_t) 0;
   1406 
   1407     /* set the tag name */
   1408     if (tagname != NULL && *tagname != '\0') {
   1409         m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
   1410         if (m_obj->tagname == NULL) {
   1411             PyErr_NoMemory();
   1412             Py_DECREF(m_obj);
   1413             return NULL;
   1414         }
   1415         strcpy(m_obj->tagname, tagname);
   1416     }
   1417     else
   1418         m_obj->tagname = NULL;
   1419 
   1420     m_obj->access = (access_mode)access;
   1421     size_hi = (DWORD)(size >> 32);
   1422     size_lo = (DWORD)(size & 0xFFFFFFFF);
   1423     off_hi = (DWORD)(offset >> 32);
   1424     off_lo = (DWORD)(offset & 0xFFFFFFFF);
   1425     /* For files, it would be sufficient to pass 0 as size.
   1426        For anonymous maps, we have to pass the size explicitly. */
   1427     m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
   1428                                           NULL,
   1429                                           flProtect,
   1430                                           size_hi,
   1431                                           size_lo,
   1432                                           m_obj->tagname);
   1433     if (m_obj->map_handle != NULL) {
   1434         m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
   1435                                              dwDesiredAccess,
   1436                                              off_hi,
   1437                                              off_lo,
   1438                                              m_obj->size);
   1439         if (m_obj->data != NULL)
   1440             return (PyObject *)m_obj;
   1441         else {
   1442             dwErr = GetLastError();
   1443             CloseHandle(m_obj->map_handle);
   1444             m_obj->map_handle = NULL;
   1445         }
   1446     } else
   1447         dwErr = GetLastError();
   1448     Py_DECREF(m_obj);
   1449     PyErr_SetFromWindowsErr(dwErr);
   1450     return NULL;
   1451 }
   1452 #endif /* MS_WINDOWS */
   1453 
   1454 static void
   1455 setint(PyObject *d, const char *name, long value)
   1456 {
   1457     PyObject *o = PyInt_FromLong(value);
   1458     if (o && PyDict_SetItemString(d, name, o) == 0) {
   1459         Py_DECREF(o);
   1460     }
   1461 }
   1462 
   1463 PyMODINIT_FUNC
   1464 initmmap(void)
   1465 {
   1466     PyObject *dict, *module;
   1467 
   1468     if (PyType_Ready(&mmap_object_type) < 0)
   1469         return;
   1470 
   1471     module = Py_InitModule("mmap", NULL);
   1472     if (module == NULL)
   1473         return;
   1474     dict = PyModule_GetDict(module);
   1475     if (!dict)
   1476         return;
   1477     mmap_module_error = PyErr_NewException("mmap.error",
   1478         PyExc_EnvironmentError , NULL);
   1479     if (mmap_module_error == NULL)
   1480         return;
   1481     PyDict_SetItemString(dict, "error", mmap_module_error);
   1482     PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
   1483 #ifdef PROT_EXEC
   1484     setint(dict, "PROT_EXEC", PROT_EXEC);
   1485 #endif
   1486 #ifdef PROT_READ
   1487     setint(dict, "PROT_READ", PROT_READ);
   1488 #endif
   1489 #ifdef PROT_WRITE
   1490     setint(dict, "PROT_WRITE", PROT_WRITE);
   1491 #endif
   1492 
   1493 #ifdef MAP_SHARED
   1494     setint(dict, "MAP_SHARED", MAP_SHARED);
   1495 #endif
   1496 #ifdef MAP_PRIVATE
   1497     setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
   1498 #endif
   1499 #ifdef MAP_DENYWRITE
   1500     setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
   1501 #endif
   1502 #ifdef MAP_EXECUTABLE
   1503     setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
   1504 #endif
   1505 #ifdef MAP_ANONYMOUS
   1506     setint(dict, "MAP_ANON", MAP_ANONYMOUS);
   1507     setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
   1508 #endif
   1509 
   1510     setint(dict, "PAGESIZE", (long)my_getpagesize());
   1511 
   1512     setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
   1513 
   1514     setint(dict, "ACCESS_READ", ACCESS_READ);
   1515     setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
   1516     setint(dict, "ACCESS_COPY", ACCESS_COPY);
   1517 }
   1518