blob: 66f0e481690e39e667719039a0ed0044e3fd78c6 [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;
119 char * where = (self->data+self->pos);
120 CHECK_VALID(NULL);
121 if ((where >= 0) && (where < (self->data+self->size))) {
122 value = (char) *(where);
123 self->pos += 1;
124 return Py_BuildValue("c", (char) *(where));
125 } else {
126 PyErr_SetString (PyExc_ValueError, "read byte out of range");
127 return NULL;
128 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000129}
130
131static PyObject *
132mmap_read_line_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000133 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000134{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000135 char * start;
136 char * eof = self->data+self->size;
137 char * eol;
138 PyObject * result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000139
Guido van Rossum09fdf072000-03-31 01:17:07 +0000140 CHECK_VALID(NULL);
141 start = self->data+self->pos;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000142
Guido van Rossum09fdf072000-03-31 01:17:07 +0000143 /* strchr was a bad idea here - there's no way to range
144 check it. there is no 'strnchr' */
145 for (eol = start; (eol < eof) && (*eol != '\n') ; eol++)
146 { /* do nothing */ }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000147
Guido van Rossum09fdf072000-03-31 01:17:07 +0000148 result = Py_BuildValue("s#", start, (long) (++eol - start));
149 self->pos += (eol - start);
150 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000151}
152
153static PyObject *
154mmap_read_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000155 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000156{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000157 long num_bytes;
158 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000159
Guido van Rossum09fdf072000-03-31 01:17:07 +0000160 CHECK_VALID(NULL);
161 if (!PyArg_ParseTuple (args, "l", &num_bytes))
162 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000163
Guido van Rossum09fdf072000-03-31 01:17:07 +0000164 /* silently 'adjust' out-of-range requests */
165 if ((self->pos + num_bytes) > self->size) {
166 num_bytes -= (self->pos+num_bytes) - self->size;
167 }
168 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
169 self->pos += num_bytes;
170 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000171}
172
173static PyObject *
174mmap_find_method (mmap_object *self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000175 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000176{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000177 long start = self->pos;
178 char * needle;
179 int len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000180
Guido van Rossum09fdf072000-03-31 01:17:07 +0000181 CHECK_VALID(NULL);
182 if (!PyArg_ParseTuple (args, "s#|l", &needle, &len, &start)) {
183 return NULL;
184 } else {
185 char * p = self->data+self->pos;
186 char * e = self->data+self->size;
187 while (p < e) {
188 char * s = p;
189 char * n = needle;
190 while ((s<e) && (*n) && !(*s-*n)) {
191 s++, n++;
192 }
193 if (!*n) {
194 return Py_BuildValue (
195 "l",
196 (long) (p - (self->data + start)));
197 }
198 p++;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000199 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000200 return Py_BuildValue ("l", (long) -1);
201 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000202}
203
204static PyObject *
205mmap_write_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000206 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000207{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000208 long length;
209 char * data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000210
Guido van Rossum09fdf072000-03-31 01:17:07 +0000211 CHECK_VALID(NULL);
212 if (!PyArg_ParseTuple (args, "s#", &data, &length))
213 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000214
Guido van Rossum09fdf072000-03-31 01:17:07 +0000215 if ((self->pos + length) > self->size) {
216 PyErr_SetString (PyExc_ValueError, "data out of range");
217 return NULL;
218 }
219 memcpy (self->data+self->pos, data, length);
220 self->pos = self->pos+length;
221 Py_INCREF (Py_None);
222 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000223}
224
225static PyObject *
226mmap_write_byte_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000227 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000228{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000229 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000230
Guido van Rossum09fdf072000-03-31 01:17:07 +0000231 CHECK_VALID(NULL);
232 if (!PyArg_ParseTuple (args, "c", &value))
233 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000234
Guido van Rossum09fdf072000-03-31 01:17:07 +0000235 *(self->data+self->pos) = value;
236 self->pos += 1;
237 Py_INCREF (Py_None);
238 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000239}
240
241static PyObject *
242mmap_size_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000243 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000244{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000245 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000246
247#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000248 if (self->file_handle != (HFILE) 0xFFFFFFFF) {
249 return (Py_BuildValue (
250 "l",
251 GetFileSize ((HANDLE)self->file_handle, NULL)));
252 } else {
253 return (Py_BuildValue ("l", self->size) );
254 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000255#endif /* MS_WIN32 */
256
257#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000258 return (Py_BuildValue ("l", self->size) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000259#endif /* UNIX */
260}
261
262/* This assumes that you want the entire file mapped,
263 / and when recreating the map will make the new file
264 / have the new size
265 /
266 / Is this really necessary? This could easily be done
267 / from python by just closing and re-opening with the
268 / new size?
269 */
270
271static PyObject *
272mmap_resize_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000273 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000274{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000275 unsigned long new_size;
276 CHECK_VALID(NULL);
277 if (!PyArg_ParseTuple (args, "l", &new_size)) {
278 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000279#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000280 } else {
281 DWORD dwErrCode = 0;
282 /* First, unmap the file view */
283 UnmapViewOfFile (self->data);
284 /* Close the mapping object */
285 CloseHandle ((HANDLE)self->map_handle);
286 /* Move to the desired EOF position */
287 SetFilePointer ((HANDLE)self->file_handle,
288 new_size, NULL, FILE_BEGIN);
289 /* Change the size of the file */
290 SetEndOfFile ((HANDLE)self->file_handle);
291 /* Create another mapping object and remap the file view */
292 self->map_handle = CreateFileMapping (
293 (HANDLE) self->file_handle,
294 NULL,
295 PAGE_READWRITE,
296 0,
297 new_size,
298 self->tagname);
299 if (self->map_handle != NULL) {
300 self->data = (char *) MapViewOfFile (self->map_handle,
301 FILE_MAP_WRITE,
302 0,
303 0,
304 0);
305 if (self->data != NULL) {
306 self->size = new_size;
307 Py_INCREF (Py_None);
308 return Py_None;
309 } else {
310 dwErrCode = GetLastError();
311 }
312 } else {
313 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000314 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000315 PyErr_SetFromWindowsErr(dwErrCode);
316 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000317#endif /* MS_WIN32 */
318
319#ifdef UNIX
320#ifndef MREMAP_MAYMOVE
321} else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000322 PyErr_SetString(PyExc_SystemError,
323 "mmap: resizing not available--no mremap()");
324 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000325#else
326} else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000327 void *newmap;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000328
Guido van Rossum09fdf072000-03-31 01:17:07 +0000329 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
330 if (newmap == (void *)-1)
331 {
332 PyErr_SetFromErrno(mmap_module_error);
333 return NULL;
334 }
335 self->data = newmap;
336 self->size = new_size;
337 Py_INCREF(Py_None);
338 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000339#endif /* MREMAP_MAYMOVE */
340#endif /* UNIX */
341}
342}
343
344static PyObject *
345mmap_tell_method (mmap_object * self, PyObject * args)
346{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000347 CHECK_VALID(NULL);
348 return (Py_BuildValue ("l", self->pos) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000349}
350
351static PyObject *
352mmap_flush_method (mmap_object * self, PyObject * args)
353{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000354 size_t offset = 0;
355 size_t size = self->size;
356 CHECK_VALID(NULL);
357 if (!PyArg_ParseTuple (args, "|ll", &offset, &size)) {
358 return NULL;
359 } else if ((offset + size) > self->size) {
360 PyErr_SetString (PyExc_ValueError,
361 "flush values out of range");
362 return NULL;
363 } else {
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000364#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000365 return (Py_BuildValue (
366 "l", FlushViewOfFile (self->data+offset, size)));
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000367#endif /* MS_WIN32 */
368#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000369 /* XXX semantics of return value? */
370 /* XXX flags for msync? */
371 if (-1 == msync(self->data + offset, size,
372 MS_SYNC | MS_INVALIDATE))
373 {
374 PyErr_SetFromErrno(mmap_module_error);
375 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000376 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000377 return Py_BuildValue ("l", 0);
378#endif /* UNIX */
379 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000380}
381
382static PyObject *
383mmap_seek_method (mmap_object * self, PyObject * args)
384{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000385 /* ptrdiff_t dist; */
386 long dist;
387 int how=0;
388 CHECK_VALID(NULL);
389 if (!PyArg_ParseTuple (args, "l|i", &dist, &how)) {
390 return(NULL);
391 } else {
392 unsigned long where;
393 switch (how) {
394 case 0:
395 where = dist;
396 break;
397 case 1:
398 where = self->pos + dist;
399 break;
400 case 2:
401 where = self->size - dist;
402 break;
403 default:
404 PyErr_SetString (PyExc_ValueError,
405 "unknown seek type");
406 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000407 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000408 if ((where >= 0) && (where < (self->size))) {
409 self->pos = where;
410 Py_INCREF (Py_None);
411 return (Py_None);
412 } else {
413 PyErr_SetString (PyExc_ValueError,
414 "seek out of range");
415 return NULL;
416 }
417 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000418}
419
420static PyObject *
421mmap_move_method (mmap_object * self, PyObject * args)
422{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000423 unsigned long dest, src, count;
424 CHECK_VALID(NULL);
425 if (!PyArg_ParseTuple (args, "iii", &dest, &src, &count)) {
426 return NULL;
427 } else {
428 /* bounds check the values */
429 if (/* end of source after end of data?? */
430 ((src+count) > self->size)
431 /* dest will fit? */
432 || (dest+count > self->size)) {
433 PyErr_SetString (PyExc_ValueError,
434 "source or destination out of range");
435 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000436 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000437 memmove (self->data+dest, self->data+src, count);
438 Py_INCREF (Py_None);
439 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000440 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000441 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000442}
443
444static struct PyMethodDef mmap_object_methods[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000445 {"close", (PyCFunction) mmap_close_method, 1},
446 {"find", (PyCFunction) mmap_find_method, 1},
447 {"flush", (PyCFunction) mmap_flush_method, 1},
448 {"move", (PyCFunction) mmap_move_method, 1},
449 {"read", (PyCFunction) mmap_read_method, 1},
450 {"read_byte", (PyCFunction) mmap_read_byte_method, 1},
451 {"readline", (PyCFunction) mmap_read_line_method, 1},
452 {"resize", (PyCFunction) mmap_resize_method, 1},
453 {"seek", (PyCFunction) mmap_seek_method, 1},
454 {"size", (PyCFunction) mmap_size_method, 1},
455 {"tell", (PyCFunction) mmap_tell_method, 1},
456 {"write", (PyCFunction) mmap_write_method, 1},
457 {"write_byte", (PyCFunction) mmap_write_byte_method, 1},
458 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000459};
460
461/* Functions for treating an mmap'ed file as a buffer */
462
463static int
464mmap_buffer_getreadbuf(self, index, ptr)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000465 mmap_object *self;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000466int index;
467const void **ptr;
468{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000469 CHECK_VALID(-1);
470 if ( index != 0 ) {
471 PyErr_SetString(PyExc_SystemError,
472 "Accessing non-existent mmap segment");
473 return -1;
474 }
475 *ptr = self->data;
476 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000477}
478
479static int
480mmap_buffer_getwritebuf(self, index, ptr)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000481 mmap_object *self;
482 int index;
483 const void **ptr;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000484{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000485 CHECK_VALID(-1);
486 if ( index != 0 ) {
487 PyErr_SetString(PyExc_SystemError,
488 "Accessing non-existent mmap segment");
489 return -1;
490 }
491 *ptr = self->data;
492 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000493}
494
495static int
496mmap_buffer_getsegcount(self, lenp)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000497 mmap_object *self;
498 int *lenp;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000499{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000500 CHECK_VALID(-1);
501 if (lenp)
502 *lenp = self->size;
503 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000504}
505
506static int
507mmap_buffer_getcharbuffer(self, index, ptr)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000508 mmap_object *self;
509 int index;
510 const void **ptr;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000511{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000512 if ( index != 0 ) {
513 PyErr_SetString(PyExc_SystemError,
514 "accessing non-existent buffer segment");
515 return -1;
516 }
517 *ptr = (const char *)self->data;
518 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000519}
520
521static PyObject *
522mmap_object_getattr(mmap_object * self, char * name)
523{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000524 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000525}
526
527static int
528mmap_length(self)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000529 mmap_object *self;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000530{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000531 CHECK_VALID(-1);
532 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000533}
534
535static PyObject *
536mmap_item(self, i)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000537 mmap_object *self;
538 int i;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000539{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000540 CHECK_VALID(NULL);
541 if (i < 0 || i >= self->size) {
542 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
543 return NULL;
544 }
545 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000546}
547
548static PyObject *
549mmap_slice(self, ilow, ihigh)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000550 mmap_object *self;
551 int ilow, ihigh;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000552{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000553 CHECK_VALID(NULL);
554 if (ilow < 0)
555 ilow = 0;
556 else if (ilow > self->size)
557 ilow = self->size;
558 if (ihigh < 0)
559 ihigh = 0;
560 if (ihigh < ilow)
561 ihigh = ilow;
562 else if (ihigh > self->size)
563 ihigh = self->size;
564
565 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000566}
567
568static PyObject *
569mmap_concat(self, bb)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000570 mmap_object *self;
571 PyObject *bb;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000572{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000573 CHECK_VALID(NULL);
574 PyErr_SetString(PyExc_SystemError,
575 "mmaps don't support concatenation");
576 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000577}
578
579static PyObject *
580mmap_repeat(self, n)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000581 mmap_object *self;
582 int n;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000583{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000584 CHECK_VALID(NULL);
585 PyErr_SetString(PyExc_SystemError,
586 "mmaps don't support repeat operation");
587 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000588}
589
590static int
591mmap_ass_slice(self, ilow, ihigh, v)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000592 mmap_object *self;
593 int ilow, ihigh;
594 PyObject *v;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000595{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000596 unsigned char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000597
Guido van Rossum09fdf072000-03-31 01:17:07 +0000598 CHECK_VALID(-1);
599 if (ilow < 0)
600 ilow = 0;
601 else if (ilow > self->size)
602 ilow = self->size;
603 if (ihigh < 0)
604 ihigh = 0;
605 if (ihigh < ilow)
606 ihigh = ilow;
607 else if (ihigh > self->size)
608 ihigh = self->size;
609
610 if (! (PyString_Check(v)) ) {
611 PyErr_SetString(PyExc_IndexError,
612 "mmap slice assignment must be a string");
613 return -1;
614 }
615 if ( PyString_Size(v) != (ihigh - ilow) ) {
616 PyErr_SetString(PyExc_IndexError,
617 "mmap slice assignment is wrong size");
618 return -1;
619 }
620 buf = PyString_AsString(v);
621 memcpy(self->data + ilow, buf, ihigh-ilow);
622 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000623}
624
625static int
626mmap_ass_item(self, i, v)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000627 mmap_object *self;
628 int i;
629 PyObject *v;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000630{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000631 unsigned char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000632
Guido van Rossum09fdf072000-03-31 01:17:07 +0000633 CHECK_VALID(-1);
634 if (i < 0 || i >= self->size) {
635 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
636 return -1;
637 }
638 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
639 PyErr_SetString(PyExc_IndexError,
640 "mmap assignment must be single-character string");
641 return -1;
642 }
643 buf = PyString_AsString(v);
644 self->data[i] = buf[0];
645 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000646}
647
648static PySequenceMethods mmap_as_sequence = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000649 (inquiry)mmap_length, /*sq_length*/
650 (binaryfunc)mmap_concat, /*sq_concat*/
651 (intargfunc)mmap_repeat, /*sq_repeat*/
652 (intargfunc)mmap_item, /*sq_item*/
653 (intintargfunc)mmap_slice, /*sq_slice*/
654 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
655 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000656};
657
658static PyBufferProcs mmap_as_buffer = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000659 (getreadbufferproc)mmap_buffer_getreadbuf,
660 (getwritebufferproc)mmap_buffer_getwritebuf,
661 (getsegcountproc)mmap_buffer_getsegcount,
662 (getcharbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000663};
664
665static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000666 PyObject_HEAD_INIT(0) /* patched in module init */
667 0, /* ob_size */
668 "mmap", /* tp_name */
669 sizeof(mmap_object), /* tp_size */
670 0, /* tp_itemsize */
671 /* methods */
672 (destructor) mmap_object_dealloc, /* tp_dealloc */
673 0, /* tp_print */
674 (getattrfunc) mmap_object_getattr, /* tp_getattr */
675 0, /* tp_setattr */
676 0, /* tp_compare */
677 0, /* tp_repr */
678 0, /* tp_as_number */
679 &mmap_as_sequence, /*tp_as_sequence*/
680 0, /*tp_as_mapping*/
681 0, /*tp_hash*/
682 0, /*tp_call*/
683 0, /*tp_str*/
684 0, /*tp_getattro*/
685 0, /*tp_setattro*/
686 &mmap_as_buffer, /*tp_as_buffer*/
687 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
688 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000689};
690
691#ifdef UNIX
692static PyObject *
693new_mmap_object (PyObject * self, PyObject * args, PyObject *kwdict)
694{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000695 mmap_object * m_obj;
696 unsigned long map_size;
697 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
698 char * filename;
699 int namelen;
700 char *keywords[] = {"file", "size", "flags", "prot", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000701
Guido van Rossum09fdf072000-03-31 01:17:07 +0000702 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
703 "il|ii", keywords,
704 &fd, &map_size, &flags, &prot)
705 )
706 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000707
Guido van Rossum09fdf072000-03-31 01:17:07 +0000708 m_obj = PyObject_NEW (mmap_object, &mmap_object_type);
709 if (m_obj == NULL) {return NULL;}
710 m_obj->size = (size_t) map_size;
711 m_obj->pos = (size_t) 0;
712 m_obj->data = mmap(NULL, map_size,
713 prot, flags,
714 fd, 0);
715 if (m_obj->data == (void *)-1)
716 {
717 Py_DECREF(m_obj);
718 PyErr_SetFromErrno(mmap_module_error);
719 return NULL;
720 }
721 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000722}
723#endif /* UNIX */
724
725#ifdef MS_WIN32
726static PyObject *
727new_mmap_object (PyObject * self, PyObject * args)
728{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000729 mmap_object * m_obj;
730 unsigned long map_size;
731 char * filename;
732 int namelen;
733 char * tagname = "";
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000734
Guido van Rossum09fdf072000-03-31 01:17:07 +0000735 DWORD dwErr = 0;
736 int fileno;
737 HFILE fh = 0;
738 OFSTRUCT file_info;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000739
Guido van Rossum09fdf072000-03-31 01:17:07 +0000740 /* Patch the object type */
741 mmap_object_type.ob_type = &PyType_Type;
742
743 if (!PyArg_ParseTuple(args,
744 "il|z",
745 &fileno,
746 &map_size,
747 &tagname)
748 )
749 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000750
Guido van Rossum09fdf072000-03-31 01:17:07 +0000751 /* if an actual filename has been specified */
752 if (fileno != 0) {
753 fh = _get_osfhandle(fileno);
754 if (fh==-1) {
755 PyErr_SetFromErrno(mmap_module_error);
756 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000757 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000758//
759// fh = OpenFile (filename, &file_info, OF_READWRITE);
760// if (fh == HFILE_ERROR) {
761// PyErr_SetFromWindowsErr(GetLastError());
762// return NULL;
763// }
764 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000765
Guido van Rossum09fdf072000-03-31 01:17:07 +0000766 m_obj = PyObject_NEW (mmap_object, &mmap_object_type);
767
768 if (fh) {
769 m_obj->file_handle = fh;
770 if (!map_size) {
771 m_obj->size = GetFileSize ((HANDLE)fh, NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000772 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000773 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000774 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000775 }
776 else {
777 m_obj->file_handle = (HFILE) 0xFFFFFFFF;
778 m_obj->size = map_size;
779 }
780
781 /* set the initial position */
782 m_obj->pos = (size_t) 0;
783
784 m_obj->map_handle = CreateFileMapping ((HANDLE) m_obj->file_handle,
785 NULL,
786 PAGE_READWRITE,
787 0,
788 m_obj->size,
789 tagname);
790 if (m_obj->map_handle != NULL) {
791 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
792 FILE_MAP_WRITE,
793 0,
794 0,
795 0);
796 if (m_obj->data != NULL) {
797 return ((PyObject *) m_obj);
798 } else {
799 dwErr = GetLastError();
800 }
801 } else {
802 dwErr = GetLastError();
803 }
804 PyErr_SetFromWindowsErr(dwErr);
805 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000806}
807#endif /* MS_WIN32 */
808
809/* List of functions exported by this module */
810static struct PyMethodDef mmap_functions[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000811 {"mmap", (PyCFunction) new_mmap_object,
812 METH_VARARGS|METH_KEYWORDS},
813 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000814};
815
816#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000817__declspec(dllexport) void
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000818#endif /* MS_WIN32 */
819#ifdef UNIX
820extern void
821#endif
822
823initmmap(void)
824{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000825 PyObject *dict, *module;
826 module = Py_InitModule ("mmap", mmap_functions);
827 dict = PyModule_GetDict (module);
828 mmap_module_error = PyExc_EnvironmentError;
829 Py_INCREF(mmap_module_error);
830 PyDict_SetItemString (dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000831#ifdef PROT_EXEC
Guido van Rossum09fdf072000-03-31 01:17:07 +0000832 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000833#endif
834#ifdef PROT_READ
Guido van Rossum09fdf072000-03-31 01:17:07 +0000835 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000836#endif
837#ifdef PROT_WRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000838 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000839#endif
840
841#ifdef MAP_SHARED
Guido van Rossum09fdf072000-03-31 01:17:07 +0000842 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000843#endif
844#ifdef MAP_PRIVATE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000845 PyDict_SetItemString (dict, "MAP_PRIVATE",
846 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000847#endif
848#ifdef MAP_DENYWRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000849 PyDict_SetItemString (dict, "MAP_DENYWRITE",
850 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000851#endif
852#ifdef MAP_EXECUTABLE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000853 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
854 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000855#endif
856#ifdef MAP_ANON
Guido van Rossum09fdf072000-03-31 01:17:07 +0000857 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
858 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
859 PyInt_FromLong(MAP_ANON) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000860#endif
861
862#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000863 PyDict_SetItemString (dict, "PAGESIZE",
864 PyInt_FromLong( (long)getpagesize() ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000865#endif
Guido van Rossum09fdf072000-03-31 01:17:07 +0000866#ifdef MS_WIN32
867 {
868 SYSTEM_INFO si;
869 GetSystemInfo(&si);
870 PyDict_SetItemString (dict, "PAGESIZE",
871 PyInt_FromLong( si.dwPageSize ) );
872 }
873#endif /* MS_WIN32 */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000874
875}