blob: 08ba085a0d638abbee15f4bbf73eba46b2d5e49a [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>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000032#include <sys/stat.h>
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000033#endif
34
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000035#include <string.h>
36#include <sys/types.h>
37
38static PyObject *mmap_module_error;
39
40typedef struct {
Guido van Rossum09fdf072000-03-31 01:17:07 +000041 PyObject_HEAD
42 char * data;
43 size_t size;
44 size_t pos;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000045
46#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +000047 HANDLE map_handle;
48 HFILE file_handle;
49 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000050#endif
51
52#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000053 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000054#endif
55} mmap_object;
56
57static void
58mmap_object_dealloc(mmap_object * m_obj)
59{
60#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +000061 UnmapViewOfFile (m_obj->data);
62 CloseHandle (m_obj->map_handle);
63 CloseHandle ((HANDLE)m_obj->file_handle);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000064#endif /* MS_WIN32 */
65
66#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +000067 if (m_obj->data!=NULL) {
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +000068 msync(m_obj->data, m_obj->size, MS_SYNC);
Guido van Rossum09fdf072000-03-31 01:17:07 +000069 munmap(m_obj->data, m_obj->size);
70 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000071#endif /* UNIX */
72
Guido van Rossumb18618d2000-05-03 23:44:39 +000073 PyObject_Del(m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000074}
75
76static PyObject *
77mmap_close_method (mmap_object * self, PyObject * args)
78{
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +000079 if (!PyArg_ParseTuple(args, ":close"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +000080 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000081#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +000082 UnmapViewOfFile (self->data);
83 CloseHandle (self->map_handle);
84 CloseHandle ((HANDLE)self->file_handle);
85 self->map_handle = (HANDLE) NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000086#endif /* MS_WIN32 */
87
88#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +000089 munmap(self->data, self->size);
90 self->data = NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000091#endif
92
Guido van Rossum09fdf072000-03-31 01:17:07 +000093 Py_INCREF (Py_None);
94 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000095}
96
97#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +000098#define CHECK_VALID(err) \
99do { \
100 if (!self->map_handle) { \
101 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
102 return err; \
103 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000104} while (0)
105#endif /* MS_WIN32 */
106
107#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000108#define CHECK_VALID(err) \
109do { \
110 if (self->data == NULL) { \
111 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
112 return err; \
113 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000114} while (0)
115#endif /* UNIX */
116
117static PyObject *
118mmap_read_byte_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000119 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000120{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000121 char value;
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000122 char * where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000123 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000124 if (!PyArg_ParseTuple(args, ":read_byte"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000125 return NULL;
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000126 if (self->pos >= 0 && self->pos < self->size) {
127 where = self->data + self->pos;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000128 value = (char) *(where);
129 self->pos += 1;
130 return Py_BuildValue("c", (char) *(where));
131 } else {
132 PyErr_SetString (PyExc_ValueError, "read byte out of range");
133 return NULL;
134 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000135}
136
137static PyObject *
138mmap_read_line_method (mmap_object * self,
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000139 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000140{
Fred Drake56a87a02000-04-04 18:17:35 +0000141 char * start = self->data+self->pos;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000142 char * eof = self->data+self->size;
143 char * eol;
144 PyObject * result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000145
Guido van Rossum09fdf072000-03-31 01:17:07 +0000146 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000147 if (!PyArg_ParseTuple(args, ":readline"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000148 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000149
Fred Drake56a87a02000-04-04 18:17:35 +0000150 eol = memchr(start, '\n', self->size - self->pos);
151 if (!eol)
152 eol = eof;
153 else
154 ++eol; /* we're interested in the position after the
155 newline. */
156 result = PyString_FromStringAndSize(start, (long) (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000157 self->pos += (eol - start);
158 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000159}
160
161static PyObject *
162mmap_read_method (mmap_object * self,
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000163 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000164{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000165 long num_bytes;
166 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000167
Guido van Rossum09fdf072000-03-31 01:17:07 +0000168 CHECK_VALID(NULL);
169 if (!PyArg_ParseTuple (args, "l", &num_bytes))
170 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000171
Guido van Rossum09fdf072000-03-31 01:17:07 +0000172 /* silently 'adjust' out-of-range requests */
173 if ((self->pos + num_bytes) > self->size) {
174 num_bytes -= (self->pos+num_bytes) - self->size;
175 }
176 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
177 self->pos += num_bytes;
178 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000179}
180
181static PyObject *
182mmap_find_method (mmap_object *self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000183 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000184{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000185 long start = self->pos;
186 char * needle;
187 int len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000188
Guido van Rossum09fdf072000-03-31 01:17:07 +0000189 CHECK_VALID(NULL);
190 if (!PyArg_ParseTuple (args, "s#|l", &needle, &len, &start)) {
191 return NULL;
192 } else {
193 char * p = self->data+self->pos;
194 char * e = self->data+self->size;
195 while (p < e) {
196 char * s = p;
197 char * n = needle;
198 while ((s<e) && (*n) && !(*s-*n)) {
199 s++, n++;
200 }
201 if (!*n) {
202 return Py_BuildValue (
203 "l",
204 (long) (p - (self->data + start)));
205 }
206 p++;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000207 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000208 return Py_BuildValue ("l", (long) -1);
209 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000210}
211
212static PyObject *
213mmap_write_method (mmap_object * self,
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000214 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000215{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000216 long length;
217 char * data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000218
Guido van Rossum09fdf072000-03-31 01:17:07 +0000219 CHECK_VALID(NULL);
220 if (!PyArg_ParseTuple (args, "s#", &data, &length))
221 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000222
Guido van Rossum09fdf072000-03-31 01:17:07 +0000223 if ((self->pos + length) > self->size) {
224 PyErr_SetString (PyExc_ValueError, "data out of range");
225 return NULL;
226 }
227 memcpy (self->data+self->pos, data, length);
228 self->pos = self->pos+length;
229 Py_INCREF (Py_None);
230 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000231}
232
233static PyObject *
234mmap_write_byte_method (mmap_object * self,
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000235 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000236{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000237 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000238
Guido van Rossum09fdf072000-03-31 01:17:07 +0000239 CHECK_VALID(NULL);
240 if (!PyArg_ParseTuple (args, "c", &value))
241 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000242
Guido van Rossum09fdf072000-03-31 01:17:07 +0000243 *(self->data+self->pos) = value;
244 self->pos += 1;
245 Py_INCREF (Py_None);
246 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000247}
248
249static PyObject *
250mmap_size_method (mmap_object * self,
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000251 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000252{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000253 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000254 if (!PyArg_ParseTuple(args, ":size"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000255 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000256
257#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000258 if (self->file_handle != (HFILE) 0xFFFFFFFF) {
259 return (Py_BuildValue (
260 "l",
261 GetFileSize ((HANDLE)self->file_handle, NULL)));
262 } else {
263 return (Py_BuildValue ("l", self->size) );
264 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000265#endif /* MS_WIN32 */
266
267#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000268 {
269 struct stat buf;
270 if (-1 == fstat(self->fd, &buf)) {
271 PyErr_SetFromErrno(mmap_module_error);
272 return NULL;
273 }
274 return (Py_BuildValue ("l", buf.st_size) );
275 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000276#endif /* UNIX */
277}
278
279/* This assumes that you want the entire file mapped,
280 / and when recreating the map will make the new file
281 / have the new size
282 /
283 / Is this really necessary? This could easily be done
284 / from python by just closing and re-opening with the
285 / new size?
286 */
287
288static PyObject *
289mmap_resize_method (mmap_object * self,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000290 PyObject * args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000291{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000292 unsigned long new_size;
293 CHECK_VALID(NULL);
294 if (!PyArg_ParseTuple (args, "l", &new_size)) {
295 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000296#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000297 } else {
298 DWORD dwErrCode = 0;
299 /* First, unmap the file view */
300 UnmapViewOfFile (self->data);
301 /* Close the mapping object */
302 CloseHandle ((HANDLE)self->map_handle);
303 /* Move to the desired EOF position */
304 SetFilePointer ((HANDLE)self->file_handle,
305 new_size, NULL, FILE_BEGIN);
306 /* Change the size of the file */
307 SetEndOfFile ((HANDLE)self->file_handle);
308 /* Create another mapping object and remap the file view */
309 self->map_handle = CreateFileMapping (
310 (HANDLE) self->file_handle,
311 NULL,
312 PAGE_READWRITE,
313 0,
314 new_size,
315 self->tagname);
316 if (self->map_handle != NULL) {
317 self->data = (char *) MapViewOfFile (self->map_handle,
318 FILE_MAP_WRITE,
319 0,
320 0,
321 0);
322 if (self->data != NULL) {
323 self->size = new_size;
324 Py_INCREF (Py_None);
325 return Py_None;
326 } else {
327 dwErrCode = GetLastError();
328 }
329 } else {
330 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000331 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000332 PyErr_SetFromWindowsErr(dwErrCode);
333 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000334#endif /* MS_WIN32 */
335
336#ifdef UNIX
337#ifndef MREMAP_MAYMOVE
338} else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000339 PyErr_SetString(PyExc_SystemError,
340 "mmap: resizing not available--no mremap()");
341 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000342#else
343} else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000344 void *newmap;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000345
Guido van Rossum09fdf072000-03-31 01:17:07 +0000346 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
347 if (newmap == (void *)-1)
348 {
349 PyErr_SetFromErrno(mmap_module_error);
350 return NULL;
351 }
352 self->data = newmap;
353 self->size = new_size;
354 Py_INCREF(Py_None);
355 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000356#endif /* MREMAP_MAYMOVE */
357#endif /* UNIX */
358}
359}
360
361static PyObject *
362mmap_tell_method (mmap_object * self, PyObject * args)
363{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000364 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000365 if (!PyArg_ParseTuple(args, ":tell"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000366 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000367 return (Py_BuildValue ("l", self->pos) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000368}
369
370static PyObject *
371mmap_flush_method (mmap_object * self, PyObject * args)
372{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000373 size_t offset = 0;
374 size_t size = self->size;
375 CHECK_VALID(NULL);
376 if (!PyArg_ParseTuple (args, "|ll", &offset, &size)) {
377 return NULL;
378 } else if ((offset + size) > self->size) {
379 PyErr_SetString (PyExc_ValueError,
380 "flush values out of range");
381 return NULL;
382 } else {
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000383#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000384 return (Py_BuildValue (
385 "l", FlushViewOfFile (self->data+offset, size)));
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000386#endif /* MS_WIN32 */
387#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000388 /* XXX semantics of return value? */
389 /* XXX flags for msync? */
390 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000391 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000392 {
393 PyErr_SetFromErrno(mmap_module_error);
394 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000395 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000396 return Py_BuildValue ("l", 0);
397#endif /* UNIX */
398 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000399}
400
401static PyObject *
402mmap_seek_method (mmap_object * self, PyObject * args)
403{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000404 /* ptrdiff_t dist; */
405 long dist;
406 int how=0;
407 CHECK_VALID(NULL);
408 if (!PyArg_ParseTuple (args, "l|i", &dist, &how)) {
409 return(NULL);
410 } else {
411 unsigned long where;
412 switch (how) {
413 case 0:
414 where = dist;
415 break;
416 case 1:
417 where = self->pos + dist;
418 break;
419 case 2:
420 where = self->size - dist;
421 break;
422 default:
423 PyErr_SetString (PyExc_ValueError,
424 "unknown seek type");
425 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000426 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000427 if ((where >= 0) && (where < (self->size))) {
428 self->pos = where;
429 Py_INCREF (Py_None);
430 return (Py_None);
431 } else {
432 PyErr_SetString (PyExc_ValueError,
433 "seek out of range");
434 return NULL;
435 }
436 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000437}
438
439static PyObject *
440mmap_move_method (mmap_object * self, PyObject * args)
441{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000442 unsigned long dest, src, count;
443 CHECK_VALID(NULL);
444 if (!PyArg_ParseTuple (args, "iii", &dest, &src, &count)) {
445 return NULL;
446 } else {
447 /* bounds check the values */
448 if (/* end of source after end of data?? */
449 ((src+count) > self->size)
450 /* dest will fit? */
451 || (dest+count > self->size)) {
452 PyErr_SetString (PyExc_ValueError,
453 "source or destination out of range");
454 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000455 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000456 memmove (self->data+dest, self->data+src, count);
457 Py_INCREF (Py_None);
458 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000459 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000460 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000461}
462
463static struct PyMethodDef mmap_object_methods[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000464 {"close", (PyCFunction) mmap_close_method, 1},
465 {"find", (PyCFunction) mmap_find_method, 1},
466 {"flush", (PyCFunction) mmap_flush_method, 1},
467 {"move", (PyCFunction) mmap_move_method, 1},
468 {"read", (PyCFunction) mmap_read_method, 1},
469 {"read_byte", (PyCFunction) mmap_read_byte_method, 1},
470 {"readline", (PyCFunction) mmap_read_line_method, 1},
471 {"resize", (PyCFunction) mmap_resize_method, 1},
472 {"seek", (PyCFunction) mmap_seek_method, 1},
473 {"size", (PyCFunction) mmap_size_method, 1},
474 {"tell", (PyCFunction) mmap_tell_method, 1},
475 {"write", (PyCFunction) mmap_write_method, 1},
476 {"write_byte", (PyCFunction) mmap_write_byte_method, 1},
477 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000478};
479
480/* Functions for treating an mmap'ed file as a buffer */
481
482static int
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000483mmap_buffer_getreadbuf(mmap_object *self, int index, 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_getwritebuf(self, index, ptr)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000497 mmap_object *self;
498 int index;
499 const void **ptr;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000500{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000501 CHECK_VALID(-1);
502 if ( index != 0 ) {
503 PyErr_SetString(PyExc_SystemError,
504 "Accessing non-existent mmap segment");
505 return -1;
506 }
507 *ptr = self->data;
508 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000509}
510
511static int
512mmap_buffer_getsegcount(self, lenp)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000513 mmap_object *self;
514 int *lenp;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000515{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000516 CHECK_VALID(-1);
517 if (lenp)
518 *lenp = self->size;
519 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000520}
521
522static int
523mmap_buffer_getcharbuffer(self, index, ptr)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000524 mmap_object *self;
525 int index;
526 const void **ptr;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000527{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000528 if ( index != 0 ) {
529 PyErr_SetString(PyExc_SystemError,
530 "accessing non-existent buffer segment");
531 return -1;
532 }
533 *ptr = (const char *)self->data;
534 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000535}
536
537static PyObject *
538mmap_object_getattr(mmap_object * self, char * name)
539{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000540 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000541}
542
543static int
544mmap_length(self)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000545 mmap_object *self;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000546{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000547 CHECK_VALID(-1);
548 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000549}
550
551static PyObject *
552mmap_item(self, i)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000553 mmap_object *self;
554 int i;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000555{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000556 CHECK_VALID(NULL);
557 if (i < 0 || i >= self->size) {
558 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
559 return NULL;
560 }
561 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000562}
563
564static PyObject *
565mmap_slice(self, ilow, ihigh)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000566 mmap_object *self;
567 int ilow, ihigh;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000568{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000569 CHECK_VALID(NULL);
570 if (ilow < 0)
571 ilow = 0;
572 else if (ilow > self->size)
573 ilow = self->size;
574 if (ihigh < 0)
575 ihigh = 0;
576 if (ihigh < ilow)
577 ihigh = ilow;
578 else if (ihigh > self->size)
579 ihigh = self->size;
580
581 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000582}
583
584static PyObject *
585mmap_concat(self, bb)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000586 mmap_object *self;
587 PyObject *bb;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000588{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000589 CHECK_VALID(NULL);
590 PyErr_SetString(PyExc_SystemError,
591 "mmaps don't support concatenation");
592 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000593}
594
595static PyObject *
596mmap_repeat(self, n)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000597 mmap_object *self;
598 int n;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000599{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000600 CHECK_VALID(NULL);
601 PyErr_SetString(PyExc_SystemError,
602 "mmaps don't support repeat operation");
603 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000604}
605
606static int
607mmap_ass_slice(self, ilow, ihigh, v)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000608 mmap_object *self;
609 int ilow, ihigh;
610 PyObject *v;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000611{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000612 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000613
Guido van Rossum09fdf072000-03-31 01:17:07 +0000614 CHECK_VALID(-1);
615 if (ilow < 0)
616 ilow = 0;
617 else if (ilow > self->size)
618 ilow = self->size;
619 if (ihigh < 0)
620 ihigh = 0;
621 if (ihigh < ilow)
622 ihigh = ilow;
623 else if (ihigh > self->size)
624 ihigh = self->size;
625
626 if (! (PyString_Check(v)) ) {
627 PyErr_SetString(PyExc_IndexError,
628 "mmap slice assignment must be a string");
629 return -1;
630 }
631 if ( PyString_Size(v) != (ihigh - ilow) ) {
632 PyErr_SetString(PyExc_IndexError,
633 "mmap slice assignment is wrong size");
634 return -1;
635 }
636 buf = PyString_AsString(v);
637 memcpy(self->data + ilow, buf, ihigh-ilow);
638 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000639}
640
641static int
642mmap_ass_item(self, i, v)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000643 mmap_object *self;
644 int i;
645 PyObject *v;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000646{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000647 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000648
Guido van Rossum09fdf072000-03-31 01:17:07 +0000649 CHECK_VALID(-1);
650 if (i < 0 || i >= self->size) {
651 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
652 return -1;
653 }
654 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
655 PyErr_SetString(PyExc_IndexError,
656 "mmap assignment must be single-character string");
657 return -1;
658 }
659 buf = PyString_AsString(v);
660 self->data[i] = buf[0];
661 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000662}
663
664static PySequenceMethods mmap_as_sequence = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000665 (inquiry)mmap_length, /*sq_length*/
666 (binaryfunc)mmap_concat, /*sq_concat*/
667 (intargfunc)mmap_repeat, /*sq_repeat*/
668 (intargfunc)mmap_item, /*sq_item*/
669 (intintargfunc)mmap_slice, /*sq_slice*/
670 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
671 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000672};
673
674static PyBufferProcs mmap_as_buffer = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000675 (getreadbufferproc)mmap_buffer_getreadbuf,
676 (getwritebufferproc)mmap_buffer_getwritebuf,
677 (getsegcountproc)mmap_buffer_getsegcount,
678 (getcharbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000679};
680
681static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000682 PyObject_HEAD_INIT(0) /* patched in module init */
683 0, /* ob_size */
684 "mmap", /* tp_name */
685 sizeof(mmap_object), /* tp_size */
686 0, /* tp_itemsize */
687 /* methods */
688 (destructor) mmap_object_dealloc, /* tp_dealloc */
689 0, /* tp_print */
690 (getattrfunc) mmap_object_getattr, /* tp_getattr */
691 0, /* tp_setattr */
692 0, /* tp_compare */
693 0, /* tp_repr */
694 0, /* tp_as_number */
695 &mmap_as_sequence, /*tp_as_sequence*/
696 0, /*tp_as_mapping*/
697 0, /*tp_hash*/
698 0, /*tp_call*/
699 0, /*tp_str*/
700 0, /*tp_getattro*/
701 0, /*tp_setattro*/
702 &mmap_as_buffer, /*tp_as_buffer*/
703 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
704 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000705};
706
707#ifdef UNIX
708static PyObject *
709new_mmap_object (PyObject * self, PyObject * args, PyObject *kwdict)
710{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000711 mmap_object * m_obj;
712 unsigned long map_size;
713 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
714 char * filename;
715 int namelen;
716 char *keywords[] = {"file", "size", "flags", "prot", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000717
Guido van Rossum09fdf072000-03-31 01:17:07 +0000718 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
719 "il|ii", keywords,
720 &fd, &map_size, &flags, &prot)
721 )
722 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000723
Guido van Rossumb18618d2000-05-03 23:44:39 +0000724 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000725 if (m_obj == NULL) {return NULL;}
726 m_obj->size = (size_t) map_size;
727 m_obj->pos = (size_t) 0;
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000728 m_obj->fd = fd;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000729 m_obj->data = mmap(NULL, map_size,
730 prot, flags,
731 fd, 0);
732 if (m_obj->data == (void *)-1)
733 {
734 Py_DECREF(m_obj);
735 PyErr_SetFromErrno(mmap_module_error);
736 return NULL;
737 }
738 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000739}
740#endif /* UNIX */
741
742#ifdef MS_WIN32
743static PyObject *
744new_mmap_object (PyObject * self, PyObject * args)
745{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000746 mmap_object * m_obj;
747 unsigned long map_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000748 char * tagname = "";
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000749
Guido van Rossum09fdf072000-03-31 01:17:07 +0000750 DWORD dwErr = 0;
751 int fileno;
752 HFILE fh = 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000753
Guido van Rossum09fdf072000-03-31 01:17:07 +0000754 /* Patch the object type */
755 mmap_object_type.ob_type = &PyType_Type;
756
757 if (!PyArg_ParseTuple(args,
758 "il|z",
759 &fileno,
760 &map_size,
761 &tagname)
762 )
763 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000764
Guido van Rossum09fdf072000-03-31 01:17:07 +0000765 /* if an actual filename has been specified */
766 if (fileno != 0) {
767 fh = _get_osfhandle(fileno);
768 if (fh==-1) {
769 PyErr_SetFromErrno(mmap_module_error);
770 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000771 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +0000772 /* Win9x appears to need us seeked to zero */
773 fseek(&_iob[fileno], 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000774 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000775
Guido van Rossumb18618d2000-05-03 23:44:39 +0000776 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000777
778 if (fh) {
779 m_obj->file_handle = fh;
780 if (!map_size) {
781 m_obj->size = GetFileSize ((HANDLE)fh, NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000782 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000783 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000784 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000785 }
786 else {
787 m_obj->file_handle = (HFILE) 0xFFFFFFFF;
788 m_obj->size = map_size;
789 }
790
791 /* set the initial position */
792 m_obj->pos = (size_t) 0;
793
794 m_obj->map_handle = CreateFileMapping ((HANDLE) m_obj->file_handle,
795 NULL,
796 PAGE_READWRITE,
797 0,
798 m_obj->size,
799 tagname);
800 if (m_obj->map_handle != NULL) {
801 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
802 FILE_MAP_WRITE,
803 0,
804 0,
805 0);
806 if (m_obj->data != NULL) {
807 return ((PyObject *) m_obj);
808 } else {
809 dwErr = GetLastError();
810 }
811 } else {
812 dwErr = GetLastError();
813 }
814 PyErr_SetFromWindowsErr(dwErr);
815 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000816}
817#endif /* MS_WIN32 */
818
819/* List of functions exported by this module */
820static struct PyMethodDef mmap_functions[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000821 {"mmap", (PyCFunction) new_mmap_object,
822 METH_VARARGS|METH_KEYWORDS},
823 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000824};
825
826#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000827__declspec(dllexport) void
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000828#endif /* MS_WIN32 */
829#ifdef UNIX
830extern void
831#endif
832
833initmmap(void)
834{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000835 PyObject *dict, *module;
836 module = Py_InitModule ("mmap", mmap_functions);
837 dict = PyModule_GetDict (module);
838 mmap_module_error = PyExc_EnvironmentError;
839 Py_INCREF(mmap_module_error);
840 PyDict_SetItemString (dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000841#ifdef PROT_EXEC
Guido van Rossum09fdf072000-03-31 01:17:07 +0000842 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000843#endif
844#ifdef PROT_READ
Guido van Rossum09fdf072000-03-31 01:17:07 +0000845 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000846#endif
847#ifdef PROT_WRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000848 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000849#endif
850
851#ifdef MAP_SHARED
Guido van Rossum09fdf072000-03-31 01:17:07 +0000852 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000853#endif
854#ifdef MAP_PRIVATE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000855 PyDict_SetItemString (dict, "MAP_PRIVATE",
856 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000857#endif
858#ifdef MAP_DENYWRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000859 PyDict_SetItemString (dict, "MAP_DENYWRITE",
860 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000861#endif
862#ifdef MAP_EXECUTABLE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000863 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
864 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000865#endif
866#ifdef MAP_ANON
Guido van Rossum09fdf072000-03-31 01:17:07 +0000867 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
868 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
869 PyInt_FromLong(MAP_ANON) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000870#endif
871
872#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000873 PyDict_SetItemString (dict, "PAGESIZE",
874 PyInt_FromLong( (long)getpagesize() ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000875#endif
Guido van Rossum09fdf072000-03-31 01:17:07 +0000876#ifdef MS_WIN32
877 {
878 SYSTEM_INFO si;
879 GetSystemInfo(&si);
880 PyDict_SetItemString (dict, "PAGESIZE",
881 PyInt_FromLong( si.dwPageSize ) );
882 }
883#endif /* MS_WIN32 */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000884
885}
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000886