blob: 377002a269d65aa5e6bfbe521f53cf0a1257315c [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 Rossumb18618d2000-05-03 23:44:39 +000072 PyObject_Del(m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000073}
74
75static PyObject *
76mmap_close_method (mmap_object * self, PyObject * args)
77{
Andrew M. Kuchling961fe172000-06-03 19:41:42 +000078 if (!PyArg_NoArgs(args))
79 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000080#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +000081 UnmapViewOfFile (self->data);
82 CloseHandle (self->map_handle);
83 CloseHandle ((HANDLE)self->file_handle);
84 self->map_handle = (HANDLE) NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000085#endif /* MS_WIN32 */
86
87#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +000088 munmap(self->data, self->size);
89 self->data = NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000090#endif
91
Guido van Rossum09fdf072000-03-31 01:17:07 +000092 Py_INCREF (Py_None);
93 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000094}
95
96#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +000097#define CHECK_VALID(err) \
98do { \
99 if (!self->map_handle) { \
100 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
101 return err; \
102 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000103} while (0)
104#endif /* MS_WIN32 */
105
106#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000107#define CHECK_VALID(err) \
108do { \
109 if (self->data == NULL) { \
110 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
111 return err; \
112 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000113} while (0)
114#endif /* UNIX */
115
116static PyObject *
117mmap_read_byte_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000118 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000119{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000120 char value;
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000121 char * where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000122 CHECK_VALID(NULL);
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000123 if (!PyArg_NoArgs(args))
124 return NULL;
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000125 if (self->pos >= 0 && self->pos < self->size) {
126 where = self->data + self->pos;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000127 value = (char) *(where);
128 self->pos += 1;
129 return Py_BuildValue("c", (char) *(where));
130 } else {
131 PyErr_SetString (PyExc_ValueError, "read byte out of range");
132 return NULL;
133 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000134}
135
136static PyObject *
137mmap_read_line_method (mmap_object * self,
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000138 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000139{
Fred Drake56a87a02000-04-04 18:17:35 +0000140 char * start = self->data+self->pos;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000141 char * eof = self->data+self->size;
142 char * eol;
143 PyObject * result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000144
Guido van Rossum09fdf072000-03-31 01:17:07 +0000145 CHECK_VALID(NULL);
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000146 if (!PyArg_NoArgs(args))
147 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000148
Fred Drake56a87a02000-04-04 18:17:35 +0000149 eol = memchr(start, '\n', self->size - self->pos);
150 if (!eol)
151 eol = eof;
152 else
153 ++eol; /* we're interested in the position after the
154 newline. */
155 result = PyString_FromStringAndSize(start, (long) (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000156 self->pos += (eol - start);
157 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000158}
159
160static PyObject *
161mmap_read_method (mmap_object * self,
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000162 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000163{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000164 long num_bytes;
165 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000166
Guido van Rossum09fdf072000-03-31 01:17:07 +0000167 CHECK_VALID(NULL);
168 if (!PyArg_ParseTuple (args, "l", &num_bytes))
169 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000170
Guido van Rossum09fdf072000-03-31 01:17:07 +0000171 /* silently 'adjust' out-of-range requests */
172 if ((self->pos + num_bytes) > self->size) {
173 num_bytes -= (self->pos+num_bytes) - self->size;
174 }
175 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
176 self->pos += num_bytes;
177 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000178}
179
180static PyObject *
181mmap_find_method (mmap_object *self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000182 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000183{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000184 long start = self->pos;
185 char * needle;
186 int len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000187
Guido van Rossum09fdf072000-03-31 01:17:07 +0000188 CHECK_VALID(NULL);
189 if (!PyArg_ParseTuple (args, "s#|l", &needle, &len, &start)) {
190 return NULL;
191 } else {
192 char * p = self->data+self->pos;
193 char * e = self->data+self->size;
194 while (p < e) {
195 char * s = p;
196 char * n = needle;
197 while ((s<e) && (*n) && !(*s-*n)) {
198 s++, n++;
199 }
200 if (!*n) {
201 return Py_BuildValue (
202 "l",
203 (long) (p - (self->data + start)));
204 }
205 p++;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000206 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000207 return Py_BuildValue ("l", (long) -1);
208 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000209}
210
211static PyObject *
212mmap_write_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000213 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000214{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000215 long length;
216 char * data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000217
Guido van Rossum09fdf072000-03-31 01:17:07 +0000218 CHECK_VALID(NULL);
219 if (!PyArg_ParseTuple (args, "s#", &data, &length))
220 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000221
Guido van Rossum09fdf072000-03-31 01:17:07 +0000222 if ((self->pos + length) > self->size) {
223 PyErr_SetString (PyExc_ValueError, "data out of range");
224 return NULL;
225 }
226 memcpy (self->data+self->pos, data, length);
227 self->pos = self->pos+length;
228 Py_INCREF (Py_None);
229 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000230}
231
232static PyObject *
233mmap_write_byte_method (mmap_object * self,
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000234 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000235{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000236 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000237
Guido van Rossum09fdf072000-03-31 01:17:07 +0000238 CHECK_VALID(NULL);
239 if (!PyArg_ParseTuple (args, "c", &value))
240 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000241
Guido van Rossum09fdf072000-03-31 01:17:07 +0000242 *(self->data+self->pos) = value;
243 self->pos += 1;
244 Py_INCREF (Py_None);
245 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000246}
247
248static PyObject *
249mmap_size_method (mmap_object * self,
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000250 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000251{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000252 CHECK_VALID(NULL);
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000253 if (!PyArg_NoArgs(args))
254 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000255
256#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000257 if (self->file_handle != (HFILE) 0xFFFFFFFF) {
258 return (Py_BuildValue (
259 "l",
260 GetFileSize ((HANDLE)self->file_handle, NULL)));
261 } else {
262 return (Py_BuildValue ("l", self->size) );
263 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000264#endif /* MS_WIN32 */
265
266#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000267 return (Py_BuildValue ("l", self->size) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000268#endif /* UNIX */
269}
270
271/* This assumes that you want the entire file mapped,
272 / and when recreating the map will make the new file
273 / have the new size
274 /
275 / Is this really necessary? This could easily be done
276 / from python by just closing and re-opening with the
277 / new size?
278 */
279
280static PyObject *
281mmap_resize_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000282 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000283{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000284 unsigned long new_size;
285 CHECK_VALID(NULL);
286 if (!PyArg_ParseTuple (args, "l", &new_size)) {
287 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000288#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000289 } else {
290 DWORD dwErrCode = 0;
291 /* First, unmap the file view */
292 UnmapViewOfFile (self->data);
293 /* Close the mapping object */
294 CloseHandle ((HANDLE)self->map_handle);
295 /* Move to the desired EOF position */
296 SetFilePointer ((HANDLE)self->file_handle,
297 new_size, NULL, FILE_BEGIN);
298 /* Change the size of the file */
299 SetEndOfFile ((HANDLE)self->file_handle);
300 /* Create another mapping object and remap the file view */
301 self->map_handle = CreateFileMapping (
302 (HANDLE) self->file_handle,
303 NULL,
304 PAGE_READWRITE,
305 0,
306 new_size,
307 self->tagname);
308 if (self->map_handle != NULL) {
309 self->data = (char *) MapViewOfFile (self->map_handle,
310 FILE_MAP_WRITE,
311 0,
312 0,
313 0);
314 if (self->data != NULL) {
315 self->size = new_size;
316 Py_INCREF (Py_None);
317 return Py_None;
318 } else {
319 dwErrCode = GetLastError();
320 }
321 } else {
322 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000323 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000324 PyErr_SetFromWindowsErr(dwErrCode);
325 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000326#endif /* MS_WIN32 */
327
328#ifdef UNIX
329#ifndef MREMAP_MAYMOVE
330} else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000331 PyErr_SetString(PyExc_SystemError,
332 "mmap: resizing not available--no mremap()");
333 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000334#else
335} else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000336 void *newmap;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000337
Guido van Rossum09fdf072000-03-31 01:17:07 +0000338 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
339 if (newmap == (void *)-1)
340 {
341 PyErr_SetFromErrno(mmap_module_error);
342 return NULL;
343 }
344 self->data = newmap;
345 self->size = new_size;
346 Py_INCREF(Py_None);
347 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000348#endif /* MREMAP_MAYMOVE */
349#endif /* UNIX */
350}
351}
352
353static PyObject *
354mmap_tell_method (mmap_object * self, PyObject * args)
355{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000356 CHECK_VALID(NULL);
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000357 if (!PyArg_NoArgs(args))
358 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000359 return (Py_BuildValue ("l", self->pos) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000360}
361
362static PyObject *
363mmap_flush_method (mmap_object * self, PyObject * args)
364{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000365 size_t offset = 0;
366 size_t size = self->size;
367 CHECK_VALID(NULL);
368 if (!PyArg_ParseTuple (args, "|ll", &offset, &size)) {
369 return NULL;
370 } else if ((offset + size) > self->size) {
371 PyErr_SetString (PyExc_ValueError,
372 "flush values out of range");
373 return NULL;
374 } else {
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000375#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000376 return (Py_BuildValue (
377 "l", FlushViewOfFile (self->data+offset, size)));
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000378#endif /* MS_WIN32 */
379#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000380 /* XXX semantics of return value? */
381 /* XXX flags for msync? */
382 if (-1 == msync(self->data + offset, size,
383 MS_SYNC | MS_INVALIDATE))
384 {
385 PyErr_SetFromErrno(mmap_module_error);
386 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000387 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000388 return Py_BuildValue ("l", 0);
389#endif /* UNIX */
390 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000391}
392
393static PyObject *
394mmap_seek_method (mmap_object * self, PyObject * args)
395{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000396 /* ptrdiff_t dist; */
397 long dist;
398 int how=0;
399 CHECK_VALID(NULL);
400 if (!PyArg_ParseTuple (args, "l|i", &dist, &how)) {
401 return(NULL);
402 } else {
403 unsigned long where;
404 switch (how) {
405 case 0:
406 where = dist;
407 break;
408 case 1:
409 where = self->pos + dist;
410 break;
411 case 2:
412 where = self->size - dist;
413 break;
414 default:
415 PyErr_SetString (PyExc_ValueError,
416 "unknown seek type");
417 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000418 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000419 if ((where >= 0) && (where < (self->size))) {
420 self->pos = where;
421 Py_INCREF (Py_None);
422 return (Py_None);
423 } else {
424 PyErr_SetString (PyExc_ValueError,
425 "seek out of range");
426 return NULL;
427 }
428 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000429}
430
431static PyObject *
432mmap_move_method (mmap_object * self, PyObject * args)
433{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000434 unsigned long dest, src, count;
435 CHECK_VALID(NULL);
436 if (!PyArg_ParseTuple (args, "iii", &dest, &src, &count)) {
437 return NULL;
438 } else {
439 /* bounds check the values */
440 if (/* end of source after end of data?? */
441 ((src+count) > self->size)
442 /* dest will fit? */
443 || (dest+count > self->size)) {
444 PyErr_SetString (PyExc_ValueError,
445 "source or destination out of range");
446 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000447 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000448 memmove (self->data+dest, self->data+src, count);
449 Py_INCREF (Py_None);
450 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000451 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000452 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000453}
454
455static struct PyMethodDef mmap_object_methods[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000456 {"close", (PyCFunction) mmap_close_method, 1},
457 {"find", (PyCFunction) mmap_find_method, 1},
458 {"flush", (PyCFunction) mmap_flush_method, 1},
459 {"move", (PyCFunction) mmap_move_method, 1},
460 {"read", (PyCFunction) mmap_read_method, 1},
461 {"read_byte", (PyCFunction) mmap_read_byte_method, 1},
462 {"readline", (PyCFunction) mmap_read_line_method, 1},
463 {"resize", (PyCFunction) mmap_resize_method, 1},
464 {"seek", (PyCFunction) mmap_seek_method, 1},
465 {"size", (PyCFunction) mmap_size_method, 1},
466 {"tell", (PyCFunction) mmap_tell_method, 1},
467 {"write", (PyCFunction) mmap_write_method, 1},
468 {"write_byte", (PyCFunction) mmap_write_byte_method, 1},
469 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000470};
471
472/* Functions for treating an mmap'ed file as a buffer */
473
474static int
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000475mmap_buffer_getreadbuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000476{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000477 CHECK_VALID(-1);
478 if ( index != 0 ) {
479 PyErr_SetString(PyExc_SystemError,
480 "Accessing non-existent mmap segment");
481 return -1;
482 }
483 *ptr = self->data;
484 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000485}
486
487static int
488mmap_buffer_getwritebuf(self, index, ptr)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000489 mmap_object *self;
490 int index;
491 const void **ptr;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000492{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000493 CHECK_VALID(-1);
494 if ( index != 0 ) {
495 PyErr_SetString(PyExc_SystemError,
496 "Accessing non-existent mmap segment");
497 return -1;
498 }
499 *ptr = self->data;
500 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000501}
502
503static int
504mmap_buffer_getsegcount(self, lenp)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000505 mmap_object *self;
506 int *lenp;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000507{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000508 CHECK_VALID(-1);
509 if (lenp)
510 *lenp = self->size;
511 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000512}
513
514static int
515mmap_buffer_getcharbuffer(self, index, ptr)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000516 mmap_object *self;
517 int index;
518 const void **ptr;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000519{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000520 if ( index != 0 ) {
521 PyErr_SetString(PyExc_SystemError,
522 "accessing non-existent buffer segment");
523 return -1;
524 }
525 *ptr = (const char *)self->data;
526 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000527}
528
529static PyObject *
530mmap_object_getattr(mmap_object * self, char * name)
531{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000532 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000533}
534
535static int
536mmap_length(self)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000537 mmap_object *self;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000538{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000539 CHECK_VALID(-1);
540 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000541}
542
543static PyObject *
544mmap_item(self, i)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000545 mmap_object *self;
546 int i;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000547{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000548 CHECK_VALID(NULL);
549 if (i < 0 || i >= self->size) {
550 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
551 return NULL;
552 }
553 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000554}
555
556static PyObject *
557mmap_slice(self, ilow, ihigh)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000558 mmap_object *self;
559 int ilow, ihigh;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000560{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000561 CHECK_VALID(NULL);
562 if (ilow < 0)
563 ilow = 0;
564 else if (ilow > self->size)
565 ilow = self->size;
566 if (ihigh < 0)
567 ihigh = 0;
568 if (ihigh < ilow)
569 ihigh = ilow;
570 else if (ihigh > self->size)
571 ihigh = self->size;
572
573 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000574}
575
576static PyObject *
577mmap_concat(self, bb)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000578 mmap_object *self;
579 PyObject *bb;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000580{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000581 CHECK_VALID(NULL);
582 PyErr_SetString(PyExc_SystemError,
583 "mmaps don't support concatenation");
584 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000585}
586
587static PyObject *
588mmap_repeat(self, n)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000589 mmap_object *self;
590 int n;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000591{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000592 CHECK_VALID(NULL);
593 PyErr_SetString(PyExc_SystemError,
594 "mmaps don't support repeat operation");
595 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000596}
597
598static int
599mmap_ass_slice(self, ilow, ihigh, v)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000600 mmap_object *self;
601 int ilow, ihigh;
602 PyObject *v;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000603{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000604 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000605
Guido van Rossum09fdf072000-03-31 01:17:07 +0000606 CHECK_VALID(-1);
607 if (ilow < 0)
608 ilow = 0;
609 else if (ilow > self->size)
610 ilow = self->size;
611 if (ihigh < 0)
612 ihigh = 0;
613 if (ihigh < ilow)
614 ihigh = ilow;
615 else if (ihigh > self->size)
616 ihigh = self->size;
617
618 if (! (PyString_Check(v)) ) {
619 PyErr_SetString(PyExc_IndexError,
620 "mmap slice assignment must be a string");
621 return -1;
622 }
623 if ( PyString_Size(v) != (ihigh - ilow) ) {
624 PyErr_SetString(PyExc_IndexError,
625 "mmap slice assignment is wrong size");
626 return -1;
627 }
628 buf = PyString_AsString(v);
629 memcpy(self->data + ilow, buf, ihigh-ilow);
630 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000631}
632
633static int
634mmap_ass_item(self, i, v)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000635 mmap_object *self;
636 int i;
637 PyObject *v;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000638{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000639 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000640
Guido van Rossum09fdf072000-03-31 01:17:07 +0000641 CHECK_VALID(-1);
642 if (i < 0 || i >= self->size) {
643 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
644 return -1;
645 }
646 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
647 PyErr_SetString(PyExc_IndexError,
648 "mmap assignment must be single-character string");
649 return -1;
650 }
651 buf = PyString_AsString(v);
652 self->data[i] = buf[0];
653 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000654}
655
656static PySequenceMethods mmap_as_sequence = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000657 (inquiry)mmap_length, /*sq_length*/
658 (binaryfunc)mmap_concat, /*sq_concat*/
659 (intargfunc)mmap_repeat, /*sq_repeat*/
660 (intargfunc)mmap_item, /*sq_item*/
661 (intintargfunc)mmap_slice, /*sq_slice*/
662 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
663 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000664};
665
666static PyBufferProcs mmap_as_buffer = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000667 (getreadbufferproc)mmap_buffer_getreadbuf,
668 (getwritebufferproc)mmap_buffer_getwritebuf,
669 (getsegcountproc)mmap_buffer_getsegcount,
670 (getcharbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000671};
672
673static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000674 PyObject_HEAD_INIT(0) /* patched in module init */
675 0, /* ob_size */
676 "mmap", /* tp_name */
677 sizeof(mmap_object), /* tp_size */
678 0, /* tp_itemsize */
679 /* methods */
680 (destructor) mmap_object_dealloc, /* tp_dealloc */
681 0, /* tp_print */
682 (getattrfunc) mmap_object_getattr, /* tp_getattr */
683 0, /* tp_setattr */
684 0, /* tp_compare */
685 0, /* tp_repr */
686 0, /* tp_as_number */
687 &mmap_as_sequence, /*tp_as_sequence*/
688 0, /*tp_as_mapping*/
689 0, /*tp_hash*/
690 0, /*tp_call*/
691 0, /*tp_str*/
692 0, /*tp_getattro*/
693 0, /*tp_setattro*/
694 &mmap_as_buffer, /*tp_as_buffer*/
695 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
696 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000697};
698
699#ifdef UNIX
700static PyObject *
701new_mmap_object (PyObject * self, PyObject * args, PyObject *kwdict)
702{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000703 mmap_object * m_obj;
704 unsigned long map_size;
705 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
706 char * filename;
707 int namelen;
708 char *keywords[] = {"file", "size", "flags", "prot", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000709
Guido van Rossum09fdf072000-03-31 01:17:07 +0000710 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
711 "il|ii", keywords,
712 &fd, &map_size, &flags, &prot)
713 )
714 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000715
Guido van Rossumb18618d2000-05-03 23:44:39 +0000716 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000717 if (m_obj == NULL) {return NULL;}
718 m_obj->size = (size_t) map_size;
719 m_obj->pos = (size_t) 0;
720 m_obj->data = mmap(NULL, map_size,
721 prot, flags,
722 fd, 0);
723 if (m_obj->data == (void *)-1)
724 {
725 Py_DECREF(m_obj);
726 PyErr_SetFromErrno(mmap_module_error);
727 return NULL;
728 }
729 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000730}
731#endif /* UNIX */
732
733#ifdef MS_WIN32
734static PyObject *
735new_mmap_object (PyObject * self, PyObject * args)
736{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000737 mmap_object * m_obj;
738 unsigned long map_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000739 char * tagname = "";
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000740
Guido van Rossum09fdf072000-03-31 01:17:07 +0000741 DWORD dwErr = 0;
742 int fileno;
743 HFILE fh = 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000744
Guido van Rossum09fdf072000-03-31 01:17:07 +0000745 /* Patch the object type */
746 mmap_object_type.ob_type = &PyType_Type;
747
748 if (!PyArg_ParseTuple(args,
749 "il|z",
750 &fileno,
751 &map_size,
752 &tagname)
753 )
754 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000755
Guido van Rossum09fdf072000-03-31 01:17:07 +0000756 /* if an actual filename has been specified */
757 if (fileno != 0) {
758 fh = _get_osfhandle(fileno);
759 if (fh==-1) {
760 PyErr_SetFromErrno(mmap_module_error);
761 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000762 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +0000763 /* Win9x appears to need us seeked to zero */
764 fseek(&_iob[fileno], 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000765 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000766
Guido van Rossumb18618d2000-05-03 23:44:39 +0000767 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000768
769 if (fh) {
770 m_obj->file_handle = fh;
771 if (!map_size) {
772 m_obj->size = GetFileSize ((HANDLE)fh, NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000773 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000774 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000775 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000776 }
777 else {
778 m_obj->file_handle = (HFILE) 0xFFFFFFFF;
779 m_obj->size = map_size;
780 }
781
782 /* set the initial position */
783 m_obj->pos = (size_t) 0;
784
785 m_obj->map_handle = CreateFileMapping ((HANDLE) m_obj->file_handle,
786 NULL,
787 PAGE_READWRITE,
788 0,
789 m_obj->size,
790 tagname);
791 if (m_obj->map_handle != NULL) {
792 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
793 FILE_MAP_WRITE,
794 0,
795 0,
796 0);
797 if (m_obj->data != NULL) {
798 return ((PyObject *) m_obj);
799 } else {
800 dwErr = GetLastError();
801 }
802 } else {
803 dwErr = GetLastError();
804 }
805 PyErr_SetFromWindowsErr(dwErr);
806 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000807}
808#endif /* MS_WIN32 */
809
810/* List of functions exported by this module */
811static struct PyMethodDef mmap_functions[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000812 {"mmap", (PyCFunction) new_mmap_object,
813 METH_VARARGS|METH_KEYWORDS},
814 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000815};
816
817#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000818__declspec(dllexport) void
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000819#endif /* MS_WIN32 */
820#ifdef UNIX
821extern void
822#endif
823
824initmmap(void)
825{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000826 PyObject *dict, *module;
827 module = Py_InitModule ("mmap", mmap_functions);
828 dict = PyModule_GetDict (module);
829 mmap_module_error = PyExc_EnvironmentError;
830 Py_INCREF(mmap_module_error);
831 PyDict_SetItemString (dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000832#ifdef PROT_EXEC
Guido van Rossum09fdf072000-03-31 01:17:07 +0000833 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000834#endif
835#ifdef PROT_READ
Guido van Rossum09fdf072000-03-31 01:17:07 +0000836 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000837#endif
838#ifdef PROT_WRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000839 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000840#endif
841
842#ifdef MAP_SHARED
Guido van Rossum09fdf072000-03-31 01:17:07 +0000843 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000844#endif
845#ifdef MAP_PRIVATE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000846 PyDict_SetItemString (dict, "MAP_PRIVATE",
847 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000848#endif
849#ifdef MAP_DENYWRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000850 PyDict_SetItemString (dict, "MAP_DENYWRITE",
851 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000852#endif
853#ifdef MAP_EXECUTABLE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000854 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
855 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000856#endif
857#ifdef MAP_ANON
Guido van Rossum09fdf072000-03-31 01:17:07 +0000858 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
859 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
860 PyInt_FromLong(MAP_ANON) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000861#endif
862
863#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000864 PyDict_SetItemString (dict, "PAGESIZE",
865 PyInt_FromLong( (long)getpagesize() ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000866#endif
Guido van Rossum09fdf072000-03-31 01:17:07 +0000867#ifdef MS_WIN32
868 {
869 SYSTEM_INFO si;
870 GetSystemInfo(&si);
871 PyDict_SetItemString (dict, "PAGESIZE",
872 PyInt_FromLong( si.dwPageSize ) );
873 }
874#endif /* MS_WIN32 */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000875
876}
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000877