LCOV - code coverage report
Current view: top level - libreoffice/workdir/unxlngi6.pro/UnpackedTarball/python3/Modules - mmapmodule.c (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 462 0.0 %
Date: 2012-12-17 Functions: 0 36 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10