home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 15 / AACD15.ISO / AACD / Programming / Python2 / Python20_source / Modules / mmapmodule.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-25  |  22.8 KB  |  1,005 lines

  1. /*
  2.  /  Author: Sam Rushing <rushing@nightmare.com>
  3.  /  Hacked for Unix by A.M. Kuchling <amk1@bigfoot.com> 
  4.  /  $Id: mmapmodule.c,v 2.24 2000/10/01 17:50:46 fdrake Exp $
  5.  
  6.  / mmapmodule.cpp -- map a view of a file into memory
  7.  /
  8.  / todo: need permission flags, perhaps a 'chsize' analog
  9.  /   not all functions check range yet!!!
  10.  /
  11.  /
  12.  / Note: This module currently only deals with 32-bit file
  13.  /   sizes.
  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. #include <Python.h>
  22.  
  23. #ifndef MS_WIN32
  24. #define UNIX
  25. #endif
  26.  
  27. #ifdef MS_WIN32
  28. #include <windows.h>
  29. static int
  30. my_getpagesize(void)
  31. {
  32.     SYSTEM_INFO si;
  33.     GetSystemInfo(&si);
  34.     return si.dwPageSize;
  35. }
  36. #endif
  37.  
  38. #ifdef UNIX
  39. #include <unistd.h>
  40. #include <sys/mman.h>
  41. #include <sys/stat.h>
  42.  
  43. #ifndef MS_SYNC
  44. /* This is missing e.g. on SunOS 4.1.4 */
  45. #define MS_SYNC 0
  46. #endif
  47.  
  48. #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
  49. static int
  50. my_getpagesize(void)
  51. {
  52.     return sysconf(_SC_PAGESIZE);
  53. }
  54. #else
  55. #define my_getpagesize getpagesize
  56. #endif
  57.  
  58. #endif /* UNIX */
  59.  
  60. #include <string.h>
  61. #include <sys/types.h>
  62.  
  63. static PyObject *mmap_module_error;
  64.  
  65. typedef struct {
  66.     PyObject_HEAD
  67.     char *    data;
  68.     size_t    size;
  69.     size_t    pos;
  70.  
  71. #ifdef MS_WIN32
  72.     HANDLE    map_handle;
  73.     HANDLE    file_handle;
  74.     char *    tagname;
  75. #endif
  76.  
  77. #ifdef UNIX
  78.         int fd;
  79. #endif
  80. } mmap_object;
  81.  
  82. static void
  83. mmap_object_dealloc(mmap_object *m_obj)
  84. {
  85. #ifdef MS_WIN32
  86.     if (m_obj->data != NULL)
  87.         UnmapViewOfFile (m_obj->data);
  88.     if (m_obj->map_handle != INVALID_HANDLE_VALUE)
  89.         CloseHandle (m_obj->map_handle);
  90.     if (m_obj->file_handle != INVALID_HANDLE_VALUE)
  91.         CloseHandle (m_obj->file_handle);
  92.     if (m_obj->tagname)
  93.         PyMem_Free(m_obj->tagname);
  94. #endif /* MS_WIN32 */
  95.  
  96. #ifdef UNIX
  97.     if (m_obj->data!=NULL) {
  98.         msync(m_obj->data, m_obj->size, MS_SYNC);
  99.         munmap(m_obj->data, m_obj->size);
  100.     }
  101. #endif /* UNIX */
  102.  
  103.     PyObject_Del(m_obj);
  104. }
  105.  
  106. static PyObject *
  107. mmap_close_method(mmap_object *self, PyObject *args)
  108. {
  109.         if (!PyArg_ParseTuple(args, ":close"))
  110.         return NULL;
  111. #ifdef MS_WIN32
  112.     /* For each resource we maintain, we need to check
  113.        the value is valid, and if so, free the resource 
  114.        and set the member value to an invalid value so
  115.        the dealloc does not attempt to resource clearing
  116.        again.
  117.        TODO - should we check for errors in the close operations???
  118.     */
  119.     if (self->data != NULL) {
  120.         UnmapViewOfFile (self->data);
  121.         self->data = NULL;
  122.     }
  123.     if (self->map_handle != INVALID_HANDLE_VALUE) {
  124.         CloseHandle (self->map_handle);
  125.         self->map_handle = INVALID_HANDLE_VALUE;
  126.     }
  127.     if (self->file_handle != INVALID_HANDLE_VALUE) {
  128.         CloseHandle (self->file_handle);
  129.         self->file_handle = INVALID_HANDLE_VALUE;
  130.     }
  131. #endif /* MS_WIN32 */
  132.  
  133. #ifdef UNIX
  134.     munmap(self->data, self->size);
  135.     self->data = NULL;
  136. #endif
  137.  
  138.     Py_INCREF (Py_None);
  139.     return (Py_None);
  140. }
  141.  
  142. #ifdef MS_WIN32
  143. #define CHECK_VALID(err)                        \
  144. do {                                    \
  145.     if (!self->map_handle) {                        \
  146.     PyErr_SetString (PyExc_ValueError, "mmap closed or invalid");    \
  147.     return err;                            \
  148.     }                                    \
  149. } while (0)
  150. #endif /* MS_WIN32 */
  151.  
  152. #ifdef UNIX
  153. #define CHECK_VALID(err)                        \
  154. do {                                    \
  155.     if (self->data == NULL) {                        \
  156.     PyErr_SetString (PyExc_ValueError, "mmap closed or invalid");    \
  157.     return err;                            \
  158.     }                                \
  159. } while (0)
  160. #endif /* UNIX */
  161.  
  162. static PyObject *
  163. mmap_read_byte_method(mmap_object *self,
  164.               PyObject *args)
  165. {
  166.     char value;
  167.     char *where;
  168.     CHECK_VALID(NULL);
  169.         if (!PyArg_ParseTuple(args, ":read_byte"))
  170.         return NULL;
  171.     if (self->pos < self->size) {
  172.             where = self->data + self->pos;
  173.         value = (char) *(where);
  174.         self->pos += 1;
  175.         return Py_BuildValue("c", (char) *(where));
  176.     } else {
  177.         PyErr_SetString (PyExc_ValueError, "read byte out of range");
  178.         return NULL;
  179.     }
  180. }
  181.  
  182. static PyObject *
  183. mmap_read_line_method(mmap_object *self,
  184.              PyObject *args)
  185. {
  186.     char *start = self->data+self->pos;
  187.     char *eof = self->data+self->size;
  188.     char *eol;
  189.     PyObject *result;
  190.  
  191.     CHECK_VALID(NULL);
  192.         if (!PyArg_ParseTuple(args, ":readline"))
  193.         return NULL;
  194.  
  195.     eol = memchr(start, '\n', self->size - self->pos);
  196.     if (!eol)
  197.         eol = eof;
  198.     else
  199.         ++eol;        /* we're interested in the position after the
  200.                    newline. */
  201.     result = PyString_FromStringAndSize(start, (eol - start));
  202.     self->pos += (eol - start);
  203.     return (result);
  204. }
  205.  
  206. static PyObject *
  207. mmap_read_method(mmap_object *self,
  208.          PyObject *args)
  209. {
  210.     long num_bytes;
  211.     PyObject *result;
  212.  
  213.     CHECK_VALID(NULL);
  214.     if (!PyArg_ParseTuple(args, "l:read", &num_bytes))
  215.         return(NULL);
  216.  
  217.     /* silently 'adjust' out-of-range requests */
  218.     if ((self->pos + num_bytes) > self->size) {
  219.         num_bytes -= (self->pos+num_bytes) - self->size;
  220.     }
  221.     result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
  222.     self->pos += num_bytes;     
  223.     return (result);
  224. }
  225.  
  226. static PyObject *
  227. mmap_find_method(mmap_object *self,
  228.          PyObject *args)
  229. {
  230.     int start = self->pos;
  231.     char *needle;
  232.     int len;
  233.  
  234.     CHECK_VALID(NULL);
  235.     if (!PyArg_ParseTuple (args, "s#|i:find", &needle, &len, &start)) {
  236.         return NULL;
  237.     } else {
  238.         char *p = self->data+self->pos;
  239.         char *e = self->data+self->size;
  240.         while (p < e) {
  241.             char *s = p;
  242.             char *n = needle;
  243.             while ((s<e) && (*n) && !(*s-*n)) {
  244.                 s++, n++;
  245.             }
  246.             if (!*n) {
  247.                 return Py_BuildValue (
  248.                     "i",
  249.                     (int) (p - (self->data + start)));
  250.             }
  251.             p++;
  252.         }
  253.         return Py_BuildValue ("l", (long) -1);
  254.     }
  255. }
  256.  
  257. static PyObject *
  258. mmap_write_method(mmap_object *self,
  259.           PyObject *args)
  260. {
  261.     long length;
  262.     char *data;
  263.  
  264.     CHECK_VALID(NULL);
  265.     if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
  266.         return(NULL);
  267.  
  268.     if ((self->pos + length) > self->size) {
  269.         PyErr_SetString (PyExc_ValueError, "data out of range");
  270.         return NULL;
  271.     }
  272.     memcpy (self->data+self->pos, data, length);
  273.     self->pos = self->pos+length;
  274.     Py_INCREF (Py_None);
  275.     return (Py_None);
  276. }
  277.  
  278. static PyObject *
  279. mmap_write_byte_method(mmap_object *self,
  280.                PyObject *args)
  281. {
  282.     char value;
  283.  
  284.     CHECK_VALID(NULL);
  285.     if (!PyArg_ParseTuple (args, "c:write_byte", &value))
  286.         return(NULL);
  287.  
  288.     *(self->data+self->pos) = value;
  289.     self->pos += 1;
  290.     Py_INCREF (Py_None);
  291.     return (Py_None);
  292. }
  293.  
  294. static PyObject *
  295. mmap_size_method(mmap_object *self,
  296.          PyObject *args)
  297. {
  298.     CHECK_VALID(NULL);
  299.         if (!PyArg_ParseTuple(args, ":size"))
  300.         return NULL;
  301.  
  302. #ifdef MS_WIN32
  303.     if (self->file_handle != INVALID_HANDLE_VALUE) {
  304.         return (Py_BuildValue (
  305.             "l", (long)
  306.             GetFileSize (self->file_handle, NULL)));
  307.     } else {
  308.         return (Py_BuildValue ("l", (long) self->size) );
  309.     }
  310. #endif /* MS_WIN32 */
  311.  
  312. #ifdef UNIX
  313.     {
  314.         struct stat buf;
  315.         if (-1 == fstat(self->fd, &buf)) {
  316.             PyErr_SetFromErrno(mmap_module_error);
  317.             return NULL;
  318.         }
  319.         return (Py_BuildValue ("l", (long) buf.st_size) );
  320.     }
  321. #endif /* UNIX */
  322. }
  323.  
  324. /* This assumes that you want the entire file mapped,
  325.  / and when recreating the map will make the new file
  326.  / have the new size
  327.  /
  328.  / Is this really necessary?  This could easily be done
  329.  / from python by just closing and re-opening with the
  330.  / new size?
  331.  */
  332.  
  333. static PyObject *
  334. mmap_resize_method(mmap_object *self,
  335.            PyObject *args)
  336. {
  337.     unsigned long new_size;
  338.     CHECK_VALID(NULL);
  339.     if (!PyArg_ParseTuple (args, "l:resize", &new_size)) {
  340.         return NULL;
  341. #ifdef MS_WIN32
  342.     } else { 
  343.         DWORD dwErrCode = 0;
  344.         /* First, unmap the file view */
  345.         UnmapViewOfFile (self->data);
  346.         /* Close the mapping object */
  347.         CloseHandle (self->map_handle);
  348.         /* Move to the desired EOF position */
  349.         SetFilePointer (self->file_handle,
  350.                 new_size, NULL, FILE_BEGIN);
  351.         /* Change the size of the file */
  352.         SetEndOfFile (self->file_handle);
  353.         /* Create another mapping object and remap the file view */
  354.         self->map_handle = CreateFileMapping (
  355.             self->file_handle,
  356.             NULL,
  357.             PAGE_READWRITE,
  358.             0,
  359.             new_size,
  360.             self->tagname);
  361.         if (self->map_handle != NULL) {
  362.             self->data = (char *) MapViewOfFile (self->map_handle,
  363.                                  FILE_MAP_WRITE,
  364.                                  0,
  365.                                  0,
  366.                                  0);
  367.             if (self->data != NULL) {
  368.                 self->size = new_size;
  369.                 Py_INCREF (Py_None);
  370.                 return Py_None;
  371.             } else {
  372.                 dwErrCode = GetLastError();
  373.             }
  374.         } else {
  375.             dwErrCode = GetLastError();
  376.         }
  377.         PyErr_SetFromWindowsErr(dwErrCode);
  378.         return (NULL);
  379. #endif /* MS_WIN32 */
  380.  
  381. #ifdef UNIX
  382. #ifndef HAVE_MREMAP 
  383. } else {
  384.     PyErr_SetString(PyExc_SystemError,
  385.             "mmap: resizing not available--no mremap()");
  386.     return NULL;
  387. #else
  388. } else {
  389.     void *newmap;
  390.  
  391. #ifdef MREMAP_MAYMOVE
  392.     newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
  393. #else
  394.     newmap = mremap(self->data, self->size, new_size, 0);
  395. #endif
  396.     if (newmap == (void *)-1) 
  397.     {
  398.         PyErr_SetFromErrno(mmap_module_error);
  399.         return NULL;
  400.     }
  401.     self->data = newmap;
  402.     self->size = new_size;
  403.     Py_INCREF(Py_None);
  404.     return Py_None;
  405. #endif /* HAVE_MREMAP */
  406. #endif /* UNIX */
  407. }
  408. }
  409.  
  410. static PyObject *
  411. mmap_tell_method(mmap_object *self, PyObject *args)
  412. {
  413.     CHECK_VALID(NULL);
  414.         if (!PyArg_ParseTuple(args, ":tell"))
  415.         return NULL;
  416.     return (Py_BuildValue ("l", (long) self->pos) );
  417. }
  418.  
  419. static PyObject *
  420. mmap_flush_method(mmap_object *self, PyObject *args)
  421. {
  422.     size_t offset    = 0;
  423.     size_t size = self->size;
  424.     CHECK_VALID(NULL);
  425.     if (!PyArg_ParseTuple (args, "|ll:flush", &offset, &size)) {
  426.         return NULL;
  427.     } else if ((offset + size) > self->size) {
  428.         PyErr_SetString (PyExc_ValueError,
  429.                  "flush values out of range");
  430.         return NULL;
  431.     } else {
  432. #ifdef MS_WIN32
  433.         return (Py_BuildValue("l", (long)
  434.                                       FlushViewOfFile(self->data+offset, size)));
  435. #endif /* MS_WIN32 */
  436. #ifdef UNIX
  437.         /* XXX semantics of return value? */
  438.         /* XXX flags for msync? */
  439.         if (-1 == msync(self->data + offset, size,
  440.                 MS_SYNC))
  441.         {
  442.             PyErr_SetFromErrno(mmap_module_error);
  443.             return NULL;
  444.         }
  445.         return Py_BuildValue ("l", (long) 0);    
  446. #endif /* UNIX */   
  447.     }
  448. }
  449.  
  450. static PyObject *
  451. mmap_seek_method(mmap_object *self, PyObject *args)
  452. {
  453.     int dist;
  454.     int how=0;
  455.     CHECK_VALID(NULL);
  456.     if (!PyArg_ParseTuple (args, "i|i:seek", &dist, &how)) {
  457.         return(NULL);
  458.     } else {
  459.         size_t where;
  460.         switch (how) {
  461.         case 0: /* relative to start */
  462.             if (dist < 0)
  463.                 goto onoutofrange;
  464.             where = dist;
  465.             break;
  466.         case 1: /* relative to current position */
  467.             if ((int)self->pos + dist < 0)
  468.                 goto onoutofrange;
  469.             where = self->pos + dist;
  470.             break;
  471.         case 2: /* relative to end */
  472.             if ((int)self->size + dist < 0)
  473.                 goto onoutofrange;
  474.             where = self->size + dist;
  475.             break;
  476.         default:
  477.             PyErr_SetString (PyExc_ValueError,
  478.                      "unknown seek type");
  479.             return NULL;
  480.         }
  481.         if (where > self->size)
  482.             goto onoutofrange;
  483.         self->pos = where;
  484.         Py_INCREF (Py_None);
  485.         return (Py_None);
  486.     }
  487.  
  488. onoutofrange:
  489.     PyErr_SetString (PyExc_ValueError, "seek out of range");
  490.     return NULL;
  491. }
  492.  
  493. static PyObject *
  494. mmap_move_method(mmap_object *self, PyObject *args)
  495. {
  496.     unsigned long dest, src, count;
  497.     CHECK_VALID(NULL);
  498.     if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count)) {
  499.         return NULL;
  500.     } else {
  501.         /* bounds check the values */
  502.         if (/* end of source after end of data?? */
  503.             ((src+count) > self->size)
  504.             /* dest will fit? */
  505.             || (dest+count > self->size)) {
  506.             PyErr_SetString (PyExc_ValueError,
  507.                      "source or destination out of range");
  508.             return NULL;
  509.         } else {
  510.             memmove (self->data+dest, self->data+src, count);
  511.             Py_INCREF (Py_None);
  512.             return Py_None;
  513.         }
  514.     }
  515. }
  516.  
  517. static struct PyMethodDef mmap_object_methods[] = {
  518.     {"close",    (PyCFunction) mmap_close_method,    1},
  519.     {"find",    (PyCFunction) mmap_find_method,        1},
  520.     {"flush",    (PyCFunction) mmap_flush_method,    1},
  521.     {"move",    (PyCFunction) mmap_move_method,        1},
  522.     {"read",    (PyCFunction) mmap_read_method,        1},
  523.     {"read_byte",    (PyCFunction) mmap_read_byte_method,      1},
  524.     {"readline",    (PyCFunction) mmap_read_line_method,    1},
  525.     {"resize",    (PyCFunction) mmap_resize_method,    1},
  526.     {"seek",    (PyCFunction) mmap_seek_method,        1},
  527.     {"size",    (PyCFunction) mmap_size_method,        1},
  528.     {"tell",    (PyCFunction) mmap_tell_method,        1},
  529.     {"write",    (PyCFunction) mmap_write_method,    1},
  530.     {"write_byte",    (PyCFunction) mmap_write_byte_method,    1},
  531.     {NULL,       NULL}       /* sentinel */
  532. };
  533.  
  534. /* Functions for treating an mmap'ed file as a buffer */
  535.  
  536. static int
  537. mmap_buffer_getreadbuf(mmap_object *self, int index, const void **ptr)
  538. {
  539.     CHECK_VALID(-1);
  540.     if ( index != 0 ) {
  541.         PyErr_SetString(PyExc_SystemError,
  542.                 "Accessing non-existent mmap segment");
  543.         return -1;
  544.     }
  545.     *ptr = self->data;
  546.     return self->size;
  547. }
  548.  
  549. static int
  550. mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
  551. {  
  552.     CHECK_VALID(-1);
  553.     if ( index != 0 ) {
  554.         PyErr_SetString(PyExc_SystemError,
  555.                 "Accessing non-existent mmap segment");
  556.         return -1;
  557.     }
  558.     *ptr = self->data;
  559.     return self->size;
  560. }
  561.  
  562. static int
  563. mmap_buffer_getsegcount(mmap_object *self, int *lenp)
  564. {
  565.     CHECK_VALID(-1);
  566.     if (lenp) 
  567.         *lenp = self->size;
  568.     return 1;
  569. }
  570.  
  571. static int
  572. mmap_buffer_getcharbuffer(mmap_object *self, int index, const void **ptr)
  573. {
  574.     if ( index != 0 ) {
  575.         PyErr_SetString(PyExc_SystemError,
  576.                 "accessing non-existent buffer segment");
  577.         return -1;
  578.     }
  579.     *ptr = (const char *)self->data;
  580.     return self->size;
  581. }
  582.  
  583. static PyObject *
  584. mmap_object_getattr(mmap_object *self, char *name)
  585. {
  586.     return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
  587. }
  588.  
  589. static int
  590. mmap_length(mmap_object *self)
  591. {
  592.     CHECK_VALID(-1);
  593.     return self->size;
  594. }
  595.  
  596. static PyObject *
  597. mmap_item(mmap_object *self, int i)
  598. {
  599.     CHECK_VALID(NULL);
  600.     if (i < 0 || (size_t)i >= self->size) {
  601.         PyErr_SetString(PyExc_IndexError, "mmap index out of range");
  602.         return NULL;
  603.     }
  604.     return PyString_FromStringAndSize(self->data + i, 1);
  605. }
  606.  
  607. static PyObject *
  608. mmap_slice(mmap_object *self, int ilow, int ihigh)
  609. {
  610.     CHECK_VALID(NULL);
  611.     if (ilow < 0)
  612.         ilow = 0;
  613.     else if ((size_t)ilow > self->size)
  614.         ilow = self->size;
  615.     if (ihigh < 0)
  616.         ihigh = 0;
  617.     if (ihigh < ilow)
  618.         ihigh = ilow;
  619.     else if ((size_t)ihigh > self->size)
  620.         ihigh = self->size;
  621.     
  622.     return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
  623. }
  624.  
  625. static PyObject *
  626. mmap_concat(mmap_object *self, PyObject *bb)
  627. {
  628.     CHECK_VALID(NULL);
  629.     PyErr_SetString(PyExc_SystemError,
  630.             "mmaps don't support concatenation");
  631.     return NULL;
  632. }
  633.  
  634. static PyObject *
  635. mmap_repeat(mmap_object *self, int n)
  636. {
  637.     CHECK_VALID(NULL);
  638.     PyErr_SetString(PyExc_SystemError,
  639.             "mmaps don't support repeat operation");
  640.     return NULL;
  641. }
  642.  
  643. static int
  644. mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
  645. {
  646.     const char *buf;
  647.  
  648.     CHECK_VALID(-1);
  649.     if (ilow < 0)
  650.         ilow = 0;
  651.     else if ((size_t)ilow > self->size)
  652.         ilow = self->size;
  653.     if (ihigh < 0)
  654.         ihigh = 0;
  655.     if (ihigh < ilow)
  656.         ihigh = ilow;
  657.     else if ((size_t)ihigh > self->size)
  658.         ihigh = self->size;
  659.     
  660.     if (! (PyString_Check(v)) ) {
  661.         PyErr_SetString(PyExc_IndexError, 
  662.                 "mmap slice assignment must be a string");
  663.         return -1;
  664.     }
  665.     if ( PyString_Size(v) != (ihigh - ilow) ) {
  666.         PyErr_SetString(PyExc_IndexError, 
  667.                 "mmap slice assignment is wrong size");
  668.         return -1;
  669.     }
  670.     buf = PyString_AsString(v);
  671.     memcpy(self->data + ilow, buf, ihigh-ilow);
  672.     return 0;
  673. }
  674.  
  675. static int
  676. mmap_ass_item(mmap_object *self, int i, PyObject *v)
  677. {
  678.     const char *buf;
  679.  
  680.     CHECK_VALID(-1);
  681.     if (i < 0 || (size_t)i >= self->size) {
  682.         PyErr_SetString(PyExc_IndexError, "mmap index out of range");
  683.         return -1;
  684.     }
  685.     if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
  686.         PyErr_SetString(PyExc_IndexError, 
  687.             "mmap assignment must be single-character string");
  688.         return -1;
  689.     }
  690.     buf = PyString_AsString(v);
  691.     self->data[i] = buf[0];
  692.     return 0;
  693. }
  694.  
  695. static PySequenceMethods mmap_as_sequence = {
  696.     (inquiry)mmap_length,               /*sq_length*/
  697.     (binaryfunc)mmap_concat,           /*sq_concat*/
  698.     (intargfunc)mmap_repeat,           /*sq_repeat*/
  699.     (intargfunc)mmap_item,               /*sq_item*/
  700.     (intintargfunc)mmap_slice,           /*sq_slice*/
  701.     (intobjargproc)mmap_ass_item,           /*sq_ass_item*/
  702.     (intintobjargproc)mmap_ass_slice,      /*sq_ass_slice*/
  703. };
  704.  
  705. static PyBufferProcs mmap_as_buffer = {
  706.     (getreadbufferproc)mmap_buffer_getreadbuf,
  707.     (getwritebufferproc)mmap_buffer_getwritebuf,
  708.     (getsegcountproc)mmap_buffer_getsegcount,
  709.     (getcharbufferproc)mmap_buffer_getcharbuffer,
  710. };
  711.  
  712. static PyTypeObject mmap_object_type = {
  713.     PyObject_HEAD_INIT(0) /* patched in module init */
  714.     0,                    /* ob_size */
  715.     "mmap",                    /* tp_name */
  716.     sizeof(mmap_object),            /* tp_size */
  717.     0,                    /* tp_itemsize */
  718.     /* methods */
  719.     (destructor) mmap_object_dealloc,    /* tp_dealloc */
  720.     0,                    /* tp_print */
  721.     (getattrfunc) mmap_object_getattr,    /* tp_getattr */
  722.     0,                    /* tp_setattr */
  723.     0,                    /* tp_compare */
  724.     0,                    /* tp_repr */
  725.     0,                    /* tp_as_number */
  726.     &mmap_as_sequence,            /*tp_as_sequence*/
  727.     0,                    /*tp_as_mapping*/
  728.     0,                    /*tp_hash*/
  729.     0,                    /*tp_call*/
  730.     0,                    /*tp_str*/
  731.     0,                    /*tp_getattro*/
  732.     0,                    /*tp_setattro*/
  733.     &mmap_as_buffer,            /*tp_as_buffer*/
  734.     Py_TPFLAGS_HAVE_GETCHARBUFFER,        /*tp_flags*/
  735.     0,                    /*tp_doc*/
  736. };
  737.  
  738.  
  739. /* extract the map size from the given PyObject
  740.  
  741.    The map size is restricted to [0, INT_MAX] because this is the current
  742.    Python limitation on object sizes. Although the mmap object *could* handle
  743.    a larger map size, there is no point because all the useful operations
  744.    (len(), slicing(), sequence indexing) are limited by a C int.
  745.  
  746.    Returns -1 on error, with an appropriate Python exception raised. On
  747.    success, the map size is returned. */
  748. static int
  749. _GetMapSize(PyObject *o)
  750. {
  751.     if (PyInt_Check(o)) {
  752.         long i = PyInt_AsLong(o);
  753.         if (PyErr_Occurred())
  754.             return -1;
  755.         if (i < 0)
  756.             goto onnegoverflow;
  757.         if (i > INT_MAX)
  758.             goto onposoverflow;
  759.         return (int)i;
  760.     }
  761.     else if (PyLong_Check(o)) {
  762.         long i = PyLong_AsLong(o);
  763.         if (PyErr_Occurred()) {
  764.             /* yes negative overflow is mistaken for positive overflow
  765.                but not worth the trouble to check sign of 'i' */
  766.             if (PyErr_ExceptionMatches(PyExc_OverflowError))
  767.                 goto onposoverflow;
  768.             else
  769.                 return -1;
  770.         }
  771.         if (i < 0)
  772.             goto onnegoverflow;
  773.         if (i > INT_MAX)
  774.             goto onposoverflow;
  775.         return (int)i;
  776.     }
  777.     else {
  778.         PyErr_SetString(PyExc_TypeError,
  779.             "map size must be an integral value");
  780.         return -1;
  781.     }
  782.  
  783. onnegoverflow:
  784.     PyErr_SetString(PyExc_OverflowError,
  785.         "memory mapped size must be positive");
  786.     return -1;
  787.  
  788. onposoverflow:
  789.     PyErr_SetString(PyExc_OverflowError,
  790.         "memory mapped size is too large (limited by C int)");
  791.     return -1;
  792. }
  793.  
  794. #ifdef UNIX 
  795. static PyObject *
  796. new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
  797. {
  798.     mmap_object *m_obj;
  799.     PyObject *map_size_obj = NULL;
  800.     int map_size;
  801.     int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
  802.     char *keywords[] = {"file", "size", "flags", "prot", NULL};
  803.  
  804.     if (!PyArg_ParseTupleAndKeywords(args, kwdict, 
  805.                      "iO|ii", keywords, 
  806.                      &fd, &map_size_obj, &flags, &prot)
  807.         )
  808.         return NULL;
  809.     map_size = _GetMapSize(map_size_obj);
  810.     if (map_size < 0)
  811.         return NULL;
  812.     
  813.     m_obj = PyObject_New (mmap_object, &mmap_object_type);
  814.     if (m_obj == NULL) {return NULL;}
  815.     m_obj->size = (size_t) map_size;
  816.     m_obj->pos = (size_t) 0;
  817.     m_obj->fd = fd;
  818.     m_obj->data = mmap(NULL, map_size, 
  819.                prot, flags,
  820.                fd, 0);
  821.     if (m_obj->data == (void *)-1)
  822.     {
  823.         Py_DECREF(m_obj);
  824.         PyErr_SetFromErrno(mmap_module_error);
  825.         return NULL;
  826.     }
  827.     return (PyObject *)m_obj;
  828. }
  829. #endif /* UNIX */
  830.  
  831. #ifdef MS_WIN32
  832. static PyObject *
  833. new_mmap_object(PyObject *self, PyObject *args)
  834. {
  835.     mmap_object *m_obj;
  836.     PyObject *map_size_obj = NULL;
  837.     int map_size;
  838.     char *tagname = "";
  839.  
  840.     DWORD dwErr = 0;
  841.     int fileno;
  842.     HANDLE fh = 0;
  843.  
  844.     /* Patch the object type */
  845.     mmap_object_type.ob_type = &PyType_Type;
  846.  
  847.     if (!PyArg_ParseTuple(args,
  848.               "iO|z",
  849.               &fileno,
  850.               &map_size_obj,
  851.               &tagname)
  852.         )
  853.         return NULL;
  854.   
  855.     map_size = _GetMapSize(map_size_obj);
  856.     if (map_size < 0)
  857.         return NULL;
  858.     
  859.     /* if an actual filename has been specified */
  860.     if (fileno != 0) {
  861.         fh = (HANDLE)_get_osfhandle(fileno);
  862.         if (fh==(HANDLE)-1) {
  863.             PyErr_SetFromErrno(mmap_module_error);
  864.             return NULL;
  865.         }
  866.         /* Win9x appears to need us seeked to zero */
  867.         fseek(&_iob[fileno], 0, SEEK_SET);
  868.     }
  869.  
  870.     m_obj = PyObject_New (mmap_object, &mmap_object_type);
  871.     if (m_obj==NULL)
  872.         return NULL;
  873.     /* Set every field to an invalid marker, so we can safely
  874.        destruct the object in the face of failure */
  875.     m_obj->data = NULL;
  876.     m_obj->file_handle = INVALID_HANDLE_VALUE;
  877.     m_obj->map_handle = INVALID_HANDLE_VALUE;
  878.     m_obj->tagname = NULL;
  879.  
  880.     if (fh) {
  881.         /* It is necessary to duplicate the handle, so the
  882.            Python code can close it on us */
  883.         if (!DuplicateHandle(
  884.                 GetCurrentProcess(), /* source process handle */
  885.                 fh, /* handle to be duplicated */
  886.                 GetCurrentProcess(), /* target proc handle */
  887.                 (LPHANDLE)&m_obj->file_handle, /* result */
  888.                 0, /* access - ignored due to options value */
  889.                 FALSE, /* inherited by child processes? */
  890.                 DUPLICATE_SAME_ACCESS)) { /* options */
  891.             dwErr = GetLastError();
  892.             Py_DECREF(m_obj);
  893.             PyErr_SetFromWindowsErr(dwErr);
  894.             return NULL;
  895.         }
  896.         if (!map_size) {
  897.             m_obj->size = GetFileSize (fh, NULL);
  898.         } else {
  899.             m_obj->size = map_size;
  900.         }
  901.     }
  902.     else {
  903.         m_obj->size = map_size;
  904.     }
  905.  
  906.     /* set the initial position */
  907.     m_obj->pos = (size_t) 0;
  908.  
  909.     /* set the tag name */
  910.     if (tagname != NULL) {
  911.         m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
  912.         if (m_obj->tagname == NULL) {
  913.             PyErr_NoMemory();
  914.             Py_DECREF(m_obj);
  915.             return NULL;
  916.         }
  917.         strcpy(m_obj->tagname, tagname);
  918.     }
  919.     else
  920.         m_obj->tagname = NULL;
  921.  
  922.     m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
  923.                            NULL,
  924.                            PAGE_READWRITE,
  925.                            0,
  926.                            m_obj->size,
  927.                            tagname);
  928.     if (m_obj->map_handle != NULL) {
  929.         m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
  930.                               FILE_MAP_WRITE,
  931.                               0,
  932.                               0,
  933.                               0);
  934.         if (m_obj->data != NULL) {
  935.             return ((PyObject *) m_obj);
  936.         } else {
  937.             dwErr = GetLastError();
  938.         }
  939.     } else {
  940.         dwErr = GetLastError();
  941.     }
  942.     Py_DECREF(m_obj);
  943.     PyErr_SetFromWindowsErr(dwErr);
  944.     return (NULL);
  945. }
  946. #endif /* MS_WIN32 */
  947.  
  948. /* List of functions exported by this module */
  949. static struct PyMethodDef mmap_functions[] = {
  950.     {"mmap",    (PyCFunction) new_mmap_object, 
  951.      METH_VARARGS|METH_KEYWORDS},
  952.     {NULL,        NULL}         /* Sentinel */
  953. };
  954.  
  955. #ifdef MS_WIN32
  956. __declspec(dllexport) void
  957. #endif /* MS_WIN32 */
  958. #ifdef UNIX
  959. extern void
  960. #endif
  961.  
  962. initmmap(void)
  963. {
  964.     PyObject *dict, *module;
  965.     module = Py_InitModule ("mmap", mmap_functions);
  966.     dict = PyModule_GetDict (module);
  967.     mmap_module_error = PyExc_EnvironmentError;
  968.     Py_INCREF(mmap_module_error);
  969.     PyDict_SetItemString (dict, "error", mmap_module_error);
  970. #ifdef PROT_EXEC
  971.     PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
  972. #endif
  973. #ifdef PROT_READ
  974.     PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
  975. #endif
  976. #ifdef PROT_WRITE
  977.     PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
  978. #endif
  979.  
  980. #ifdef MAP_SHARED
  981.     PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
  982. #endif
  983. #ifdef MAP_PRIVATE
  984.     PyDict_SetItemString (dict, "MAP_PRIVATE",
  985.                   PyInt_FromLong(MAP_PRIVATE) );
  986. #endif
  987. #ifdef MAP_DENYWRITE
  988.     PyDict_SetItemString (dict, "MAP_DENYWRITE",
  989.                   PyInt_FromLong(MAP_DENYWRITE) );
  990. #endif
  991. #ifdef MAP_EXECUTABLE
  992.     PyDict_SetItemString (dict, "MAP_EXECUTABLE",
  993.                   PyInt_FromLong(MAP_EXECUTABLE) );
  994. #endif
  995. #ifdef MAP_ANON
  996.     PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
  997.     PyDict_SetItemString (dict, "MAP_ANONYMOUS",
  998.                   PyInt_FromLong(MAP_ANON) );
  999. #endif
  1000.  
  1001.     PyDict_SetItemString (dict, "PAGESIZE",
  1002.                   PyInt_FromLong( (long)my_getpagesize() ) );
  1003. }
  1004.  
  1005.