blob: a79812d9338968bfee47cfe4b91627e050005d65 [file] [log] [blame]
Guido van Rossum09fdf072000-03-31 01:17:07 +00001/*
2 / Author: Sam Rushing <rushing@nightmare.com>
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00003 / Hacked for Unix by A.M. Kuchling <amk1@bigfoot.com>
Guido van Rossum09fdf072000-03-31 01:17:07 +00004 / $Id$
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00005
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 / The latest version of mmapfile is maintained by Sam at
16 / ftp://squirl.nightmare.com/pub/python/python-ext.
17*/
18
Guido van Rossum09fdf072000-03-31 01:17:07 +000019#include <Python.h>
20
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000021#ifndef MS_WIN32
22#define UNIX
23#endif
24
25#ifdef MS_WIN32
26#include <windows.h>
27#endif
28
29#ifdef UNIX
30#include <unistd.h>
31#include <sys/mman.h>
32#endif
33
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000034#include <string.h>
35#include <sys/types.h>
36
37static PyObject *mmap_module_error;
38
39typedef struct {
Guido van Rossum09fdf072000-03-31 01:17:07 +000040 PyObject_HEAD
41 char * data;
42 size_t size;
43 size_t pos;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000044
45#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +000046 HANDLE map_handle;
47 HFILE file_handle;
48 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000049#endif
50
51#ifdef UNIX
52 /* No Unix-specific information at this point in time */
53#endif
54} mmap_object;
55
56static void
57mmap_object_dealloc(mmap_object * m_obj)
58{
59#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +000060 UnmapViewOfFile (m_obj->data);
61 CloseHandle (m_obj->map_handle);
62 CloseHandle ((HANDLE)m_obj->file_handle);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000063#endif /* MS_WIN32 */
64
65#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +000066 if (m_obj->data!=NULL) {
67 msync(m_obj->data, m_obj->size, MS_SYNC | MS_INVALIDATE);
68 munmap(m_obj->data, m_obj->size);
69 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000070#endif /* UNIX */
71
Guido van Rossum09fdf072000-03-31 01:17:07 +000072 PyMem_DEL(m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000073}
74
75static PyObject *
76mmap_close_method (mmap_object * self, PyObject * args)
77{
78#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +000079 UnmapViewOfFile (self->data);
80 CloseHandle (self->map_handle);
81 CloseHandle ((HANDLE)self->file_handle);
82 self->map_handle = (HANDLE) NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000083#endif /* MS_WIN32 */
84
85#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +000086 munmap(self->data, self->size);
87 self->data = NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000088#endif
89
Guido van Rossum09fdf072000-03-31 01:17:07 +000090 Py_INCREF (Py_None);
91 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000092}
93
94#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +000095#define CHECK_VALID(err) \
96do { \
97 if (!self->map_handle) { \
98 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
99 return err; \
100 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000101} while (0)
102#endif /* MS_WIN32 */
103
104#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000105#define CHECK_VALID(err) \
106do { \
107 if (self->data == NULL) { \
108 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
109 return err; \
110 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000111} while (0)
112#endif /* UNIX */
113
114static PyObject *
115mmap_read_byte_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000116 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000117{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000118 char value;
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000119 char * where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000120 CHECK_VALID(NULL);
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000121 if (self->pos >= 0 && self->pos < self->size) {
122 where = self->data + self->pos;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000123 value = (char) *(where);
124 self->pos += 1;
125 return Py_BuildValue("c", (char) *(where));
126 } else {
127 PyErr_SetString (PyExc_ValueError, "read byte out of range");
128 return NULL;
129 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000130}
131
132static PyObject *
133mmap_read_line_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000134 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000135{
Fred Drake56a87a02000-04-04 18:17:35 +0000136 char * start = self->data+self->pos;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000137 char * eof = self->data+self->size;
138 char * eol;
139 PyObject * result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000140
Guido van Rossum09fdf072000-03-31 01:17:07 +0000141 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000142
Fred Drake56a87a02000-04-04 18:17:35 +0000143 eol = memchr(start, '\n', self->size - self->pos);
144 if (!eol)
145 eol = eof;
146 else
147 ++eol; /* we're interested in the position after the
148 newline. */
149 result = PyString_FromStringAndSize(start, (long) (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000150 self->pos += (eol - start);
151 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000152}
153
154static PyObject *
155mmap_read_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000156 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000157{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000158 long num_bytes;
159 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000160
Guido van Rossum09fdf072000-03-31 01:17:07 +0000161 CHECK_VALID(NULL);
162 if (!PyArg_ParseTuple (args, "l", &num_bytes))
163 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000164
Guido van Rossum09fdf072000-03-31 01:17:07 +0000165 /* silently 'adjust' out-of-range requests */
166 if ((self->pos + num_bytes) > self->size) {
167 num_bytes -= (self->pos+num_bytes) - self->size;
168 }
169 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
170 self->pos += num_bytes;
171 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000172}
173
174static PyObject *
175mmap_find_method (mmap_object *self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000176 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000177{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000178 long start = self->pos;
179 char * needle;
180 int len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000181
Guido van Rossum09fdf072000-03-31 01:17:07 +0000182 CHECK_VALID(NULL);
183 if (!PyArg_ParseTuple (args, "s#|l", &needle, &len, &start)) {
184 return NULL;
185 } else {
186 char * p = self->data+self->pos;
187 char * e = self->data+self->size;
188 while (p < e) {
189 char * s = p;
190 char * n = needle;
191 while ((s<e) && (*n) && !(*s-*n)) {
192 s++, n++;
193 }
194 if (!*n) {
195 return Py_BuildValue (
196 "l",
197 (long) (p - (self->data + start)));
198 }
199 p++;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000200 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000201 return Py_BuildValue ("l", (long) -1);
202 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000203}
204
205static PyObject *
206mmap_write_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000207 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000208{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000209 long length;
210 char * data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000211
Guido van Rossum09fdf072000-03-31 01:17:07 +0000212 CHECK_VALID(NULL);
213 if (!PyArg_ParseTuple (args, "s#", &data, &length))
214 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000215
Guido van Rossum09fdf072000-03-31 01:17:07 +0000216 if ((self->pos + length) > self->size) {
217 PyErr_SetString (PyExc_ValueError, "data out of range");
218 return NULL;
219 }
220 memcpy (self->data+self->pos, data, length);
221 self->pos = self->pos+length;
222 Py_INCREF (Py_None);
223 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000224}
225
226static PyObject *
227mmap_write_byte_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000228 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000229{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000230 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000231
Guido van Rossum09fdf072000-03-31 01:17:07 +0000232 CHECK_VALID(NULL);
233 if (!PyArg_ParseTuple (args, "c", &value))
234 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000235
Guido van Rossum09fdf072000-03-31 01:17:07 +0000236 *(self->data+self->pos) = value;
237 self->pos += 1;
238 Py_INCREF (Py_None);
239 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000240}
241
242static PyObject *
243mmap_size_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000244 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000245{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000246 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000247
248#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000249 if (self->file_handle != (HFILE) 0xFFFFFFFF) {
250 return (Py_BuildValue (
251 "l",
252 GetFileSize ((HANDLE)self->file_handle, NULL)));
253 } else {
254 return (Py_BuildValue ("l", self->size) );
255 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000256#endif /* MS_WIN32 */
257
258#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000259 return (Py_BuildValue ("l", self->size) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000260#endif /* UNIX */
261}
262
263/* This assumes that you want the entire file mapped,
264 / and when recreating the map will make the new file
265 / have the new size
266 /
267 / Is this really necessary? This could easily be done
268 / from python by just closing and re-opening with the
269 / new size?
270 */
271
272static PyObject *
273mmap_resize_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000274 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000275{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000276 unsigned long new_size;
277 CHECK_VALID(NULL);
278 if (!PyArg_ParseTuple (args, "l", &new_size)) {
279 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000280#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000281 } else {
282 DWORD dwErrCode = 0;
283 /* First, unmap the file view */
284 UnmapViewOfFile (self->data);
285 /* Close the mapping object */
286 CloseHandle ((HANDLE)self->map_handle);
287 /* Move to the desired EOF position */
288 SetFilePointer ((HANDLE)self->file_handle,
289 new_size, NULL, FILE_BEGIN);
290 /* Change the size of the file */
291 SetEndOfFile ((HANDLE)self->file_handle);
292 /* Create another mapping object and remap the file view */
293 self->map_handle = CreateFileMapping (
294 (HANDLE) self->file_handle,
295 NULL,
296 PAGE_READWRITE,
297 0,
298 new_size,
299 self->tagname);
300 if (self->map_handle != NULL) {
301 self->data = (char *) MapViewOfFile (self->map_handle,
302 FILE_MAP_WRITE,
303 0,
304 0,
305 0);
306 if (self->data != NULL) {
307 self->size = new_size;
308 Py_INCREF (Py_None);
309 return Py_None;
310 } else {
311 dwErrCode = GetLastError();
312 }
313 } else {
314 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000315 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000316 PyErr_SetFromWindowsErr(dwErrCode);
317 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000318#endif /* MS_WIN32 */
319
320#ifdef UNIX
321#ifndef MREMAP_MAYMOVE
322} else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000323 PyErr_SetString(PyExc_SystemError,
324 "mmap: resizing not available--no mremap()");
325 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000326#else
327} else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000328 void *newmap;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000329
Guido van Rossum09fdf072000-03-31 01:17:07 +0000330 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
331 if (newmap == (void *)-1)
332 {
333 PyErr_SetFromErrno(mmap_module_error);
334 return NULL;
335 }
336 self->data = newmap;
337 self->size = new_size;
338 Py_INCREF(Py_None);
339 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000340#endif /* MREMAP_MAYMOVE */
341#endif /* UNIX */
342}
343}
344
345static PyObject *
346mmap_tell_method (mmap_object * self, PyObject * args)
347{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000348 CHECK_VALID(NULL);
349 return (Py_BuildValue ("l", self->pos) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000350}
351
352static PyObject *
353mmap_flush_method (mmap_object * self, PyObject * args)
354{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000355 size_t offset = 0;
356 size_t size = self->size;
357 CHECK_VALID(NULL);
358 if (!PyArg_ParseTuple (args, "|ll", &offset, &size)) {
359 return NULL;
360 } else if ((offset + size) > self->size) {
361 PyErr_SetString (PyExc_ValueError,
362 "flush values out of range");
363 return NULL;
364 } else {
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000365#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000366 return (Py_BuildValue (
367 "l", FlushViewOfFile (self->data+offset, size)));
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000368#endif /* MS_WIN32 */
369#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000370 /* XXX semantics of return value? */
371 /* XXX flags for msync? */
372 if (-1 == msync(self->data + offset, size,
373 MS_SYNC | MS_INVALIDATE))
374 {
375 PyErr_SetFromErrno(mmap_module_error);
376 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000377 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000378 return Py_BuildValue ("l", 0);
379#endif /* UNIX */
380 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000381}
382
383static PyObject *
384mmap_seek_method (mmap_object * self, PyObject * args)
385{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000386 /* ptrdiff_t dist; */
387 long dist;
388 int how=0;
389 CHECK_VALID(NULL);
390 if (!PyArg_ParseTuple (args, "l|i", &dist, &how)) {
391 return(NULL);
392 } else {
393 unsigned long where;
394 switch (how) {
395 case 0:
396 where = dist;
397 break;
398 case 1:
399 where = self->pos + dist;
400 break;
401 case 2:
402 where = self->size - dist;
403 break;
404 default:
405 PyErr_SetString (PyExc_ValueError,
406 "unknown seek type");
407 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000408 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000409 if ((where >= 0) && (where < (self->size))) {
410 self->pos = where;
411 Py_INCREF (Py_None);
412 return (Py_None);
413 } else {
414 PyErr_SetString (PyExc_ValueError,
415 "seek out of range");
416 return NULL;
417 }
418 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000419}
420
421static PyObject *
422mmap_move_method (mmap_object * self, PyObject * args)
423{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000424 unsigned long dest, src, count;
425 CHECK_VALID(NULL);
426 if (!PyArg_ParseTuple (args, "iii", &dest, &src, &count)) {
427 return NULL;
428 } else {
429 /* bounds check the values */
430 if (/* end of source after end of data?? */
431 ((src+count) > self->size)
432 /* dest will fit? */
433 || (dest+count > self->size)) {
434 PyErr_SetString (PyExc_ValueError,
435 "source or destination out of range");
436 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000437 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000438 memmove (self->data+dest, self->data+src, count);
439 Py_INCREF (Py_None);
440 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000441 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000442 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000443}
444
445static struct PyMethodDef mmap_object_methods[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000446 {"close", (PyCFunction) mmap_close_method, 1},
447 {"find", (PyCFunction) mmap_find_method, 1},
448 {"flush", (PyCFunction) mmap_flush_method, 1},
449 {"move", (PyCFunction) mmap_move_method, 1},
450 {"read", (PyCFunction) mmap_read_method, 1},
451 {"read_byte", (PyCFunction) mmap_read_byte_method, 1},
452 {"readline", (PyCFunction) mmap_read_line_method, 1},
453 {"resize", (PyCFunction) mmap_resize_method, 1},
454 {"seek", (PyCFunction) mmap_seek_method, 1},
455 {"size", (PyCFunction) mmap_size_method, 1},
456 {"tell", (PyCFunction) mmap_tell_method, 1},
457 {"write", (PyCFunction) mmap_write_method, 1},
458 {"write_byte", (PyCFunction) mmap_write_byte_method, 1},
459 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000460};
461
462/* Functions for treating an mmap'ed file as a buffer */
463
464static int
465mmap_buffer_getreadbuf(self, index, ptr)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000466 mmap_object *self;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000467int index;
468const void **ptr;
469{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000470 CHECK_VALID(-1);
471 if ( index != 0 ) {
472 PyErr_SetString(PyExc_SystemError,
473 "Accessing non-existent mmap segment");
474 return -1;
475 }
476 *ptr = self->data;
477 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000478}
479
480static int
481mmap_buffer_getwritebuf(self, index, ptr)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000482 mmap_object *self;
483 int index;
484 const void **ptr;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000485{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000486 CHECK_VALID(-1);
487 if ( index != 0 ) {
488 PyErr_SetString(PyExc_SystemError,
489 "Accessing non-existent mmap segment");
490 return -1;
491 }
492 *ptr = self->data;
493 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000494}
495
496static int
497mmap_buffer_getsegcount(self, lenp)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000498 mmap_object *self;
499 int *lenp;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000500{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000501 CHECK_VALID(-1);
502 if (lenp)
503 *lenp = self->size;
504 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000505}
506
507static int
508mmap_buffer_getcharbuffer(self, index, ptr)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000509 mmap_object *self;
510 int index;
511 const void **ptr;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000512{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000513 if ( index != 0 ) {
514 PyErr_SetString(PyExc_SystemError,
515 "accessing non-existent buffer segment");
516 return -1;
517 }
518 *ptr = (const char *)self->data;
519 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000520}
521
522static PyObject *
523mmap_object_getattr(mmap_object * self, char * name)
524{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000525 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000526}
527
528static int
529mmap_length(self)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000530 mmap_object *self;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000531{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000532 CHECK_VALID(-1);
533 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000534}
535
536static PyObject *
537mmap_item(self, i)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000538 mmap_object *self;
539 int i;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000540{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000541 CHECK_VALID(NULL);
542 if (i < 0 || i >= self->size) {
543 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
544 return NULL;
545 }
546 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000547}
548
549static PyObject *
550mmap_slice(self, ilow, ihigh)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000551 mmap_object *self;
552 int ilow, ihigh;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000553{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000554 CHECK_VALID(NULL);
555 if (ilow < 0)
556 ilow = 0;
557 else if (ilow > self->size)
558 ilow = self->size;
559 if (ihigh < 0)
560 ihigh = 0;
561 if (ihigh < ilow)
562 ihigh = ilow;
563 else if (ihigh > self->size)
564 ihigh = self->size;
565
566 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000567}
568
569static PyObject *
570mmap_concat(self, bb)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000571 mmap_object *self;
572 PyObject *bb;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000573{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000574 CHECK_VALID(NULL);
575 PyErr_SetString(PyExc_SystemError,
576 "mmaps don't support concatenation");
577 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000578}
579
580static PyObject *
581mmap_repeat(self, n)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000582 mmap_object *self;
583 int n;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000584{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000585 CHECK_VALID(NULL);
586 PyErr_SetString(PyExc_SystemError,
587 "mmaps don't support repeat operation");
588 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000589}
590
591static int
592mmap_ass_slice(self, ilow, ihigh, v)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000593 mmap_object *self;
594 int ilow, ihigh;
595 PyObject *v;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000596{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000597 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000598
Guido van Rossum09fdf072000-03-31 01:17:07 +0000599 CHECK_VALID(-1);
600 if (ilow < 0)
601 ilow = 0;
602 else if (ilow > self->size)
603 ilow = self->size;
604 if (ihigh < 0)
605 ihigh = 0;
606 if (ihigh < ilow)
607 ihigh = ilow;
608 else if (ihigh > self->size)
609 ihigh = self->size;
610
611 if (! (PyString_Check(v)) ) {
612 PyErr_SetString(PyExc_IndexError,
613 "mmap slice assignment must be a string");
614 return -1;
615 }
616 if ( PyString_Size(v) != (ihigh - ilow) ) {
617 PyErr_SetString(PyExc_IndexError,
618 "mmap slice assignment is wrong size");
619 return -1;
620 }
621 buf = PyString_AsString(v);
622 memcpy(self->data + ilow, buf, ihigh-ilow);
623 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000624}
625
626static int
627mmap_ass_item(self, i, v)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000628 mmap_object *self;
629 int i;
630 PyObject *v;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000631{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000632 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000633
Guido van Rossum09fdf072000-03-31 01:17:07 +0000634 CHECK_VALID(-1);
635 if (i < 0 || i >= self->size) {
636 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
637 return -1;
638 }
639 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
640 PyErr_SetString(PyExc_IndexError,
641 "mmap assignment must be single-character string");
642 return -1;
643 }
644 buf = PyString_AsString(v);
645 self->data[i] = buf[0];
646 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000647}
648
649static PySequenceMethods mmap_as_sequence = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000650 (inquiry)mmap_length, /*sq_length*/
651 (binaryfunc)mmap_concat, /*sq_concat*/
652 (intargfunc)mmap_repeat, /*sq_repeat*/
653 (intargfunc)mmap_item, /*sq_item*/
654 (intintargfunc)mmap_slice, /*sq_slice*/
655 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
656 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000657};
658
659static PyBufferProcs mmap_as_buffer = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000660 (getreadbufferproc)mmap_buffer_getreadbuf,
661 (getwritebufferproc)mmap_buffer_getwritebuf,
662 (getsegcountproc)mmap_buffer_getsegcount,
663 (getcharbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000664};
665
666static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000667 PyObject_HEAD_INIT(0) /* patched in module init */
668 0, /* ob_size */
669 "mmap", /* tp_name */
670 sizeof(mmap_object), /* tp_size */
671 0, /* tp_itemsize */
672 /* methods */
673 (destructor) mmap_object_dealloc, /* tp_dealloc */
674 0, /* tp_print */
675 (getattrfunc) mmap_object_getattr, /* tp_getattr */
676 0, /* tp_setattr */
677 0, /* tp_compare */
678 0, /* tp_repr */
679 0, /* tp_as_number */
680 &mmap_as_sequence, /*tp_as_sequence*/
681 0, /*tp_as_mapping*/
682 0, /*tp_hash*/
683 0, /*tp_call*/
684 0, /*tp_str*/
685 0, /*tp_getattro*/
686 0, /*tp_setattro*/
687 &mmap_as_buffer, /*tp_as_buffer*/
688 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
689 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000690};
691
692#ifdef UNIX
693static PyObject *
694new_mmap_object (PyObject * self, PyObject * args, PyObject *kwdict)
695{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000696 mmap_object * m_obj;
697 unsigned long map_size;
698 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
699 char * filename;
700 int namelen;
701 char *keywords[] = {"file", "size", "flags", "prot", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000702
Guido van Rossum09fdf072000-03-31 01:17:07 +0000703 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
704 "il|ii", keywords,
705 &fd, &map_size, &flags, &prot)
706 )
707 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000708
Guido van Rossum09fdf072000-03-31 01:17:07 +0000709 m_obj = PyObject_NEW (mmap_object, &mmap_object_type);
710 if (m_obj == NULL) {return NULL;}
711 m_obj->size = (size_t) map_size;
712 m_obj->pos = (size_t) 0;
713 m_obj->data = mmap(NULL, map_size,
714 prot, flags,
715 fd, 0);
716 if (m_obj->data == (void *)-1)
717 {
718 Py_DECREF(m_obj);
719 PyErr_SetFromErrno(mmap_module_error);
720 return NULL;
721 }
722 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000723}
724#endif /* UNIX */
725
726#ifdef MS_WIN32
727static PyObject *
728new_mmap_object (PyObject * self, PyObject * args)
729{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000730 mmap_object * m_obj;
731 unsigned long map_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000732 char * tagname = "";
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000733
Guido van Rossum09fdf072000-03-31 01:17:07 +0000734 DWORD dwErr = 0;
735 int fileno;
736 HFILE fh = 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000737
Guido van Rossum09fdf072000-03-31 01:17:07 +0000738 /* Patch the object type */
739 mmap_object_type.ob_type = &PyType_Type;
740
741 if (!PyArg_ParseTuple(args,
742 "il|z",
743 &fileno,
744 &map_size,
745 &tagname)
746 )
747 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000748
Guido van Rossum09fdf072000-03-31 01:17:07 +0000749 /* if an actual filename has been specified */
750 if (fileno != 0) {
751 fh = _get_osfhandle(fileno);
752 if (fh==-1) {
753 PyErr_SetFromErrno(mmap_module_error);
754 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000755 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +0000756 /* Win9x appears to need us seeked to zero */
757 fseek(&_iob[fileno], 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000758 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000759
Guido van Rossum09fdf072000-03-31 01:17:07 +0000760 m_obj = PyObject_NEW (mmap_object, &mmap_object_type);
761
762 if (fh) {
763 m_obj->file_handle = fh;
764 if (!map_size) {
765 m_obj->size = GetFileSize ((HANDLE)fh, NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000766 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000767 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000768 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000769 }
770 else {
771 m_obj->file_handle = (HFILE) 0xFFFFFFFF;
772 m_obj->size = map_size;
773 }
774
775 /* set the initial position */
776 m_obj->pos = (size_t) 0;
777
778 m_obj->map_handle = CreateFileMapping ((HANDLE) m_obj->file_handle,
779 NULL,
780 PAGE_READWRITE,
781 0,
782 m_obj->size,
783 tagname);
784 if (m_obj->map_handle != NULL) {
785 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
786 FILE_MAP_WRITE,
787 0,
788 0,
789 0);
790 if (m_obj->data != NULL) {
791 return ((PyObject *) m_obj);
792 } else {
793 dwErr = GetLastError();
794 }
795 } else {
796 dwErr = GetLastError();
797 }
798 PyErr_SetFromWindowsErr(dwErr);
799 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000800}
801#endif /* MS_WIN32 */
802
803/* List of functions exported by this module */
804static struct PyMethodDef mmap_functions[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000805 {"mmap", (PyCFunction) new_mmap_object,
806 METH_VARARGS|METH_KEYWORDS},
807 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000808};
809
810#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000811__declspec(dllexport) void
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000812#endif /* MS_WIN32 */
813#ifdef UNIX
814extern void
815#endif
816
817initmmap(void)
818{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000819 PyObject *dict, *module;
820 module = Py_InitModule ("mmap", mmap_functions);
821 dict = PyModule_GetDict (module);
822 mmap_module_error = PyExc_EnvironmentError;
823 Py_INCREF(mmap_module_error);
824 PyDict_SetItemString (dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000825#ifdef PROT_EXEC
Guido van Rossum09fdf072000-03-31 01:17:07 +0000826 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000827#endif
828#ifdef PROT_READ
Guido van Rossum09fdf072000-03-31 01:17:07 +0000829 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000830#endif
831#ifdef PROT_WRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000832 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000833#endif
834
835#ifdef MAP_SHARED
Guido van Rossum09fdf072000-03-31 01:17:07 +0000836 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000837#endif
838#ifdef MAP_PRIVATE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000839 PyDict_SetItemString (dict, "MAP_PRIVATE",
840 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000841#endif
842#ifdef MAP_DENYWRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000843 PyDict_SetItemString (dict, "MAP_DENYWRITE",
844 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000845#endif
846#ifdef MAP_EXECUTABLE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000847 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
848 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000849#endif
850#ifdef MAP_ANON
Guido van Rossum09fdf072000-03-31 01:17:07 +0000851 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
852 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
853 PyInt_FromLong(MAP_ANON) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000854#endif
855
856#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000857 PyDict_SetItemString (dict, "PAGESIZE",
858 PyInt_FromLong( (long)getpagesize() ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000859#endif
Guido van Rossum09fdf072000-03-31 01:17:07 +0000860#ifdef MS_WIN32
861 {
862 SYSTEM_INFO si;
863 GetSystemInfo(&si);
864 PyDict_SetItemString (dict, "PAGESIZE",
865 PyInt_FromLong( si.dwPageSize ) );
866 }
867#endif /* MS_WIN32 */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000868
869}