source: python/vendor/Python-2.7.6/Modules/mmapmodule.c

Last change on this file was 388, checked in by dmik, 11 years ago

python: Update vendor to 2.7.6.

  • Property svn:eol-style set to native
File size: 45.4 KB
Line 
1/*
2 / Author: Sam Rushing <rushing@nightmare.com>
3 / Hacked for Unix by AMK
4 / $Id$
5
6 / Modified to support mmap with offset - to map a 'window' of a file
7 / Author: Yotam Medini yotamm@mellanox.co.il
8 /
9 / mmapmodule.cpp -- map a view of a file into memory
10 /
11 / todo: need permission flags, perhaps a 'chsize' analog
12 / not all functions check range yet!!!
13 /
14 /
15 / This version of mmapmodule.c has been changed significantly
16 / from the original mmapfile.c on which it was based.
17 / The original version of mmapfile is maintained by Sam at
18 / ftp://squirl.nightmare.com/pub/python/python-ext.
19*/
20
21#define PY_SSIZE_T_CLEAN
22#include <Python.h>
23
24#ifndef MS_WINDOWS
25#define UNIX
26# ifdef __APPLE__
27# include <fcntl.h>
28# endif
29#endif
30
31#ifdef MS_WINDOWS
32#include <windows.h>
33static int
34my_getpagesize(void)
35{
36 SYSTEM_INFO si;
37 GetSystemInfo(&si);
38 return si.dwPageSize;
39}
40
41static int
42my_getallocationgranularity (void)
43{
44
45 SYSTEM_INFO si;
46 GetSystemInfo(&si);
47 return si.dwAllocationGranularity;
48}
49
50#endif
51
52#ifdef UNIX
53#include <sys/mman.h>
54#include <sys/stat.h>
55
56#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
57static int
58my_getpagesize(void)
59{
60 return sysconf(_SC_PAGESIZE);
61}
62
63#define my_getallocationgranularity my_getpagesize
64#else
65#define my_getpagesize getpagesize
66#endif
67
68#endif /* UNIX */
69
70#include <string.h>
71
72#ifdef HAVE_SYS_TYPES_H
73#include <sys/types.h>
74#endif /* HAVE_SYS_TYPES_H */
75
76/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
77#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
78# define MAP_ANONYMOUS MAP_ANON
79#endif
80
81static PyObject *mmap_module_error;
82
83typedef enum
84{
85 ACCESS_DEFAULT,
86 ACCESS_READ,
87 ACCESS_WRITE,
88 ACCESS_COPY
89} access_mode;
90
91typedef struct {
92 PyObject_HEAD
93 char * data;
94 size_t size;
95 size_t pos; /* relative to offset */
96#ifdef MS_WINDOWS
97 PY_LONG_LONG offset;
98#else
99 off_t offset;
100#endif
101
102#ifdef MS_WINDOWS
103 HANDLE map_handle;
104 HANDLE file_handle;
105 char * tagname;
106#endif
107
108#ifdef UNIX
109 int fd;
110#endif
111
112 access_mode access;
113} mmap_object;
114
115
116static void
117mmap_object_dealloc(mmap_object *m_obj)
118{
119#ifdef MS_WINDOWS
120 if (m_obj->data != NULL)
121 UnmapViewOfFile (m_obj->data);
122 if (m_obj->map_handle != NULL)
123 CloseHandle (m_obj->map_handle);
124 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
125 CloseHandle (m_obj->file_handle);
126 if (m_obj->tagname)
127 PyMem_Free(m_obj->tagname);
128#endif /* MS_WINDOWS */
129
130#ifdef UNIX
131 if (m_obj->fd >= 0)
132 (void) close(m_obj->fd);
133 if (m_obj->data!=NULL) {
134 if (m_obj->access != ACCESS_READ && m_obj->access != ACCESS_COPY)
135 msync(m_obj->data, m_obj->size, MS_SYNC);
136 munmap(m_obj->data, m_obj->size);
137 }
138#endif /* UNIX */
139
140 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
141}
142
143static PyObject *
144mmap_close_method(mmap_object *self, PyObject *unused)
145{
146#ifdef MS_WINDOWS
147 /* For each resource we maintain, we need to check
148 the value is valid, and if so, free the resource
149 and set the member value to an invalid value so
150 the dealloc does not attempt to resource clearing
151 again.
152 TODO - should we check for errors in the close operations???
153 */
154 if (self->data != NULL) {
155 UnmapViewOfFile(self->data);
156 self->data = NULL;
157 }
158 if (self->map_handle != NULL) {
159 CloseHandle(self->map_handle);
160 self->map_handle = NULL;
161 }
162 if (self->file_handle != INVALID_HANDLE_VALUE) {
163 CloseHandle(self->file_handle);
164 self->file_handle = INVALID_HANDLE_VALUE;
165 }
166#endif /* MS_WINDOWS */
167
168#ifdef UNIX
169 if (0 <= self->fd)
170 (void) close(self->fd);
171 self->fd = -1;
172 if (self->data != NULL) {
173 munmap(self->data, self->size);
174 self->data = NULL;
175 }
176#endif
177
178 Py_INCREF(Py_None);
179 return Py_None;
180}
181
182#ifdef MS_WINDOWS
183#define CHECK_VALID(err) \
184do { \
185 if (self->map_handle == NULL) { \
186 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
187 return err; \
188 } \
189} while (0)
190#endif /* MS_WINDOWS */
191
192#ifdef UNIX
193#define CHECK_VALID(err) \
194do { \
195 if (self->data == NULL) { \
196 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
197 return err; \
198 } \
199} while (0)
200#endif /* UNIX */
201
202static PyObject *
203mmap_read_byte_method(mmap_object *self,
204 PyObject *unused)
205{
206 CHECK_VALID(NULL);
207 if (self->pos < self->size) {
208 char value = self->data[self->pos];
209 self->pos += 1;
210 return Py_BuildValue("c", value);
211 } else {
212 PyErr_SetString(PyExc_ValueError, "read byte out of range");
213 return NULL;
214 }
215}
216
217static PyObject *
218mmap_read_line_method(mmap_object *self,
219 PyObject *unused)
220{
221 char *start = self->data+self->pos;
222 char *eof = self->data+self->size;
223 char *eol;
224 PyObject *result;
225
226 CHECK_VALID(NULL);
227
228 eol = memchr(start, '\n', self->size - self->pos);
229 if (!eol)
230 eol = eof;
231 else
232 ++eol; /* we're interested in the position after the
233 newline. */
234 result = PyString_FromStringAndSize(start, (eol - start));
235 self->pos += (eol - start);
236 return result;
237}
238
239static PyObject *
240mmap_read_method(mmap_object *self,
241 PyObject *args)
242{
243 Py_ssize_t num_bytes, n;
244 PyObject *result;
245
246 CHECK_VALID(NULL);
247 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
248 return(NULL);
249
250 /* silently 'adjust' out-of-range requests */
251 assert(self->size >= self->pos);
252 n = self->size - self->pos;
253 /* The difference can overflow, only if self->size is greater than
254 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
255 * because the mapped area and the returned string each need more
256 * than half of the addressable memory. So we clip the size, and let
257 * the code below raise MemoryError.
258 */
259 if (n < 0)
260 n = PY_SSIZE_T_MAX;
261 if (num_bytes < 0 || num_bytes > n) {
262 num_bytes = n;
263 }
264 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
265 self->pos += num_bytes;
266 return result;
267}
268
269static PyObject *
270mmap_gfind(mmap_object *self,
271 PyObject *args,
272 int reverse)
273{
274 Py_ssize_t start = self->pos;
275 Py_ssize_t end = self->size;
276 const char *needle;
277 Py_ssize_t len;
278
279 CHECK_VALID(NULL);
280 if (!PyArg_ParseTuple(args, reverse ? "s#|nn:rfind" : "s#|nn:find",
281 &needle, &len, &start, &end)) {
282 return NULL;
283 } else {
284 const char *p, *start_p, *end_p;
285 int sign = reverse ? -1 : 1;
286
287 if (start < 0)
288 start += self->size;
289 if (start < 0)
290 start = 0;
291 else if ((size_t)start > self->size)
292 start = self->size;
293
294 if (end < 0)
295 end += self->size;
296 if (end < 0)
297 end = 0;
298 else if ((size_t)end > self->size)
299 end = self->size;
300
301 start_p = self->data + start;
302 end_p = self->data + end;
303
304 for (p = (reverse ? end_p - len : start_p);
305 (p >= start_p) && (p + len <= end_p); p += sign) {
306 Py_ssize_t i;
307 for (i = 0; i < len && needle[i] == p[i]; ++i)
308 /* nothing */;
309 if (i == len) {
310 return PyInt_FromSsize_t(p - self->data);
311 }
312 }
313 return PyInt_FromLong(-1);
314 }
315}
316
317static PyObject *
318mmap_find_method(mmap_object *self,
319 PyObject *args)
320{
321 return mmap_gfind(self, args, 0);
322}
323
324static PyObject *
325mmap_rfind_method(mmap_object *self,
326 PyObject *args)
327{
328 return mmap_gfind(self, args, 1);
329}
330
331static int
332is_writeable(mmap_object *self)
333{
334 if (self->access != ACCESS_READ)
335 return 1;
336 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
337 return 0;
338}
339
340static int
341is_resizeable(mmap_object *self)
342{
343 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
344 return 1;
345 PyErr_Format(PyExc_TypeError,
346 "mmap can't resize a readonly or copy-on-write memory map.");
347 return 0;
348}
349
350
351static PyObject *
352mmap_write_method(mmap_object *self,
353 PyObject *args)
354{
355 Py_ssize_t length;
356 char *data;
357
358 CHECK_VALID(NULL);
359 if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
360 return(NULL);
361
362 if (!is_writeable(self))
363 return NULL;
364
365 if ((self->pos + length) > self->size) {
366 PyErr_SetString(PyExc_ValueError, "data out of range");
367 return NULL;
368 }
369 memcpy(self->data+self->pos, data, length);
370 self->pos = self->pos+length;
371 Py_INCREF(Py_None);
372 return Py_None;
373}
374
375static PyObject *
376mmap_write_byte_method(mmap_object *self,
377 PyObject *args)
378{
379 char value;
380
381 CHECK_VALID(NULL);
382 if (!PyArg_ParseTuple(args, "c:write_byte", &value))
383 return(NULL);
384
385 if (!is_writeable(self))
386 return NULL;
387
388 if (self->pos < self->size) {
389 *(self->data+self->pos) = value;
390 self->pos += 1;
391 Py_INCREF(Py_None);
392 return Py_None;
393 }
394 else {
395 PyErr_SetString(PyExc_ValueError, "write byte out of range");
396 return NULL;
397 }
398}
399
400static PyObject *
401mmap_size_method(mmap_object *self,
402 PyObject *unused)
403{
404 CHECK_VALID(NULL);
405
406#ifdef MS_WINDOWS
407 if (self->file_handle != INVALID_HANDLE_VALUE) {
408 DWORD low,high;
409 PY_LONG_LONG size;
410 low = GetFileSize(self->file_handle, &high);
411 if (low == INVALID_FILE_SIZE) {
412 /* It might be that the function appears to have failed,
413 when indeed its size equals INVALID_FILE_SIZE */
414 DWORD error = GetLastError();
415 if (error != NO_ERROR)
416 return PyErr_SetFromWindowsErr(error);
417 }
418 if (!high && low < LONG_MAX)
419 return PyInt_FromLong((long)low);
420 size = (((PY_LONG_LONG)high)<<32) + low;
421 return PyLong_FromLongLong(size);
422 } else {
423 return PyInt_FromSsize_t(self->size);
424 }
425#endif /* MS_WINDOWS */
426
427#ifdef UNIX
428 {
429 struct stat buf;
430 if (-1 == fstat(self->fd, &buf)) {
431 PyErr_SetFromErrno(mmap_module_error);
432 return NULL;
433 }
434#ifdef HAVE_LARGEFILE_SUPPORT
435 return PyLong_FromLongLong(buf.st_size);
436#else
437 return PyInt_FromLong(buf.st_size);
438#endif
439 }
440#endif /* UNIX */
441}
442
443/* This assumes that you want the entire file mapped,
444 / and when recreating the map will make the new file
445 / have the new size
446 /
447 / Is this really necessary? This could easily be done
448 / from python by just closing and re-opening with the
449 / new size?
450 */
451
452static PyObject *
453mmap_resize_method(mmap_object *self,
454 PyObject *args)
455{
456 Py_ssize_t new_size;
457 CHECK_VALID(NULL);
458 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
459 !is_resizeable(self)) {
460 return NULL;
461#ifdef MS_WINDOWS
462 } else {
463 DWORD dwErrCode = 0;
464 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
465 /* First, unmap the file view */
466 UnmapViewOfFile(self->data);
467 self->data = NULL;
468 /* Close the mapping object */
469 CloseHandle(self->map_handle);
470 self->map_handle = NULL;
471 /* Move to the desired EOF position */
472 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
473 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
474 off_hi = (DWORD)(self->offset >> 32);
475 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
476 SetFilePointer(self->file_handle,
477 newSizeLow, &newSizeHigh, FILE_BEGIN);
478 /* Change the size of the file */
479 SetEndOfFile(self->file_handle);
480 /* Create another mapping object and remap the file view */
481 self->map_handle = CreateFileMapping(
482 self->file_handle,
483 NULL,
484 PAGE_READWRITE,
485 0,
486 0,
487 self->tagname);
488 if (self->map_handle != NULL) {
489 self->data = (char *) MapViewOfFile(self->map_handle,
490 FILE_MAP_WRITE,
491 off_hi,
492 off_lo,
493 new_size);
494 if (self->data != NULL) {
495 self->size = new_size;
496 Py_INCREF(Py_None);
497 return Py_None;
498 } else {
499 dwErrCode = GetLastError();
500 CloseHandle(self->map_handle);
501 self->map_handle = NULL;
502 }
503 } else {
504 dwErrCode = GetLastError();
505 }
506 PyErr_SetFromWindowsErr(dwErrCode);
507 return NULL;
508#endif /* MS_WINDOWS */
509
510#ifdef UNIX
511#ifndef HAVE_MREMAP
512 } else {
513 PyErr_SetString(PyExc_SystemError,
514 "mmap: resizing not available--no mremap()");
515 return NULL;
516#else
517 } else {
518 void *newmap;
519
520 if (ftruncate(self->fd, self->offset + new_size) == -1) {
521 PyErr_SetFromErrno(mmap_module_error);
522 return NULL;
523 }
524
525#ifdef MREMAP_MAYMOVE
526 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
527#else
528 #if defined(__NetBSD__)
529 newmap = mremap(self->data, self->size, self->data, new_size, 0);
530 #else
531 newmap = mremap(self->data, self->size, new_size, 0);
532 #endif /* __NetBSD__ */
533#endif
534 if (newmap == (void *)-1)
535 {
536 PyErr_SetFromErrno(mmap_module_error);
537 return NULL;
538 }
539 self->data = newmap;
540 self->size = new_size;
541 Py_INCREF(Py_None);
542 return Py_None;
543#endif /* HAVE_MREMAP */
544#endif /* UNIX */
545 }
546}
547
548static PyObject *
549mmap_tell_method(mmap_object *self, PyObject *unused)
550{
551 CHECK_VALID(NULL);
552 return PyInt_FromSize_t(self->pos);
553}
554
555static PyObject *
556mmap_flush_method(mmap_object *self, PyObject *args)
557{
558 Py_ssize_t offset = 0;
559 Py_ssize_t size = self->size;
560 CHECK_VALID(NULL);
561 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
562 return NULL;
563 if ((size_t)(offset + size) > self->size) {
564 PyErr_SetString(PyExc_ValueError, "flush values out of range");
565 return NULL;
566 }
567
568 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
569 return PyLong_FromLong(0);
570
571#ifdef MS_WINDOWS
572 return PyInt_FromLong((long) FlushViewOfFile(self->data+offset, size));
573#elif defined(UNIX)
574 /* XXX semantics of return value? */
575 /* XXX flags for msync? */
576 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
577 PyErr_SetFromErrno(mmap_module_error);
578 return NULL;
579 }
580 return PyInt_FromLong(0);
581#else
582 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
583 return NULL;
584#endif
585}
586
587static PyObject *
588mmap_seek_method(mmap_object *self, PyObject *args)
589{
590 Py_ssize_t dist;
591 int how=0;
592 CHECK_VALID(NULL);
593 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
594 return NULL;
595 else {
596 size_t where;
597 switch (how) {
598 case 0: /* relative to start */
599 if (dist < 0)
600 goto onoutofrange;
601 where = dist;
602 break;
603 case 1: /* relative to current position */
604 if ((Py_ssize_t)self->pos + dist < 0)
605 goto onoutofrange;
606 where = self->pos + dist;
607 break;
608 case 2: /* relative to end */
609 if ((Py_ssize_t)self->size + dist < 0)
610 goto onoutofrange;
611 where = self->size + dist;
612 break;
613 default:
614 PyErr_SetString(PyExc_ValueError, "unknown seek type");
615 return NULL;
616 }
617 if (where > self->size)
618 goto onoutofrange;
619 self->pos = where;
620 Py_INCREF(Py_None);
621 return Py_None;
622 }
623
624 onoutofrange:
625 PyErr_SetString(PyExc_ValueError, "seek out of range");
626 return NULL;
627}
628
629static PyObject *
630mmap_move_method(mmap_object *self, PyObject *args)
631{
632 unsigned long dest, src, cnt;
633 CHECK_VALID(NULL);
634 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
635 !is_writeable(self)) {
636 return NULL;
637 } else {
638 /* bounds check the values */
639 if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt ||
640 src < 0 || src > self->size || (src + cnt) > self->size ||
641 dest < 0 || dest > self->size || (dest + cnt) > self->size) {
642 PyErr_SetString(PyExc_ValueError,
643 "source, destination, or count out of range");
644 return NULL;
645 }
646 memmove(self->data+dest, self->data+src, cnt);
647 Py_INCREF(Py_None);
648 return Py_None;
649 }
650}
651
652static struct PyMethodDef mmap_object_methods[] = {
653 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
654 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
655 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
656 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
657 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
658 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
659 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
660 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
661 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
662 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
663 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
664 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
665 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
666 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
667 {NULL, NULL} /* sentinel */
668};
669
670/* Functions for treating an mmap'ed file as a buffer */
671
672static Py_ssize_t
673mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
674{
675 CHECK_VALID(-1);
676 if (index != 0) {
677 PyErr_SetString(PyExc_SystemError,
678 "Accessing non-existent mmap segment");
679 return -1;
680 }
681 *ptr = self->data;
682 return self->size;
683}
684
685static Py_ssize_t
686mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
687{
688 CHECK_VALID(-1);
689 if (index != 0) {
690 PyErr_SetString(PyExc_SystemError,
691 "Accessing non-existent mmap segment");
692 return -1;
693 }
694 if (!is_writeable(self))
695 return -1;
696 *ptr = self->data;
697 return self->size;
698}
699
700static Py_ssize_t
701mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
702{
703 CHECK_VALID(-1);
704 if (lenp)
705 *lenp = self->size;
706 return 1;
707}
708
709static Py_ssize_t
710mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
711{
712 if (index != 0) {
713 PyErr_SetString(PyExc_SystemError,
714 "accessing non-existent buffer segment");
715 return -1;
716 }
717 *ptr = (const char *)self->data;
718 return self->size;
719}
720
721static Py_ssize_t
722mmap_length(mmap_object *self)
723{
724 CHECK_VALID(-1);
725 return self->size;
726}
727
728static PyObject *
729mmap_item(mmap_object *self, Py_ssize_t i)
730{
731 CHECK_VALID(NULL);
732 if (i < 0 || (size_t)i >= self->size) {
733 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
734 return NULL;
735 }
736 return PyString_FromStringAndSize(self->data + i, 1);
737}
738
739static PyObject *
740mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
741{
742 CHECK_VALID(NULL);
743 if (ilow < 0)
744 ilow = 0;
745 else if ((size_t)ilow > self->size)
746 ilow = self->size;
747 if (ihigh < 0)
748 ihigh = 0;
749 if (ihigh < ilow)
750 ihigh = ilow;
751 else if ((size_t)ihigh > self->size)
752 ihigh = self->size;
753
754 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
755}
756
757static PyObject *
758mmap_subscript(mmap_object *self, PyObject *item)
759{
760 CHECK_VALID(NULL);
761 if (PyIndex_Check(item)) {
762 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
763 if (i == -1 && PyErr_Occurred())
764 return NULL;
765 if (i < 0)
766 i += self->size;
767 if (i < 0 || (size_t)i >= self->size) {
768 PyErr_SetString(PyExc_IndexError,
769 "mmap index out of range");
770 return NULL;
771 }
772 return PyString_FromStringAndSize(self->data + i, 1);
773 }
774 else if (PySlice_Check(item)) {
775 Py_ssize_t start, stop, step, slicelen;
776
777 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
778 &start, &stop, &step, &slicelen) < 0) {
779 return NULL;
780 }
781
782 if (slicelen <= 0)
783 return PyString_FromStringAndSize("", 0);
784 else if (step == 1)
785 return PyString_FromStringAndSize(self->data + start,
786 slicelen);
787 else {
788 char *result_buf = (char *)PyMem_Malloc(slicelen);
789 Py_ssize_t cur, i;
790 PyObject *result;
791
792 if (result_buf == NULL)
793 return PyErr_NoMemory();
794 for (cur = start, i = 0; i < slicelen;
795 cur += step, i++) {
796 result_buf[i] = self->data[cur];
797 }
798 result = PyString_FromStringAndSize(result_buf,
799 slicelen);
800 PyMem_Free(result_buf);
801 return result;
802 }
803 }
804 else {
805 PyErr_SetString(PyExc_TypeError,
806 "mmap indices must be integers");
807 return NULL;
808 }
809}
810
811static PyObject *
812mmap_concat(mmap_object *self, PyObject *bb)
813{
814 CHECK_VALID(NULL);
815 PyErr_SetString(PyExc_SystemError,
816 "mmaps don't support concatenation");
817 return NULL;
818}
819
820static PyObject *
821mmap_repeat(mmap_object *self, Py_ssize_t n)
822{
823 CHECK_VALID(NULL);
824 PyErr_SetString(PyExc_SystemError,
825 "mmaps don't support repeat operation");
826 return NULL;
827}
828
829static int
830mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
831{
832 const char *buf;
833
834 CHECK_VALID(-1);
835 if (ilow < 0)
836 ilow = 0;
837 else if ((size_t)ilow > self->size)
838 ilow = self->size;
839 if (ihigh < 0)
840 ihigh = 0;
841 if (ihigh < ilow)
842 ihigh = ilow;
843 else if ((size_t)ihigh > self->size)
844 ihigh = self->size;
845
846 if (v == NULL) {
847 PyErr_SetString(PyExc_TypeError,
848 "mmap object doesn't support slice deletion");
849 return -1;
850 }
851 if (! (PyString_Check(v)) ) {
852 PyErr_SetString(PyExc_IndexError,
853 "mmap slice assignment must be a string");
854 return -1;
855 }
856 if (PyString_Size(v) != (ihigh - ilow)) {
857 PyErr_SetString(PyExc_IndexError,
858 "mmap slice assignment is wrong size");
859 return -1;
860 }
861 if (!is_writeable(self))
862 return -1;
863 buf = PyString_AsString(v);
864 memcpy(self->data + ilow, buf, ihigh-ilow);
865 return 0;
866}
867
868static int
869mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
870{
871 const char *buf;
872
873 CHECK_VALID(-1);
874 if (i < 0 || (size_t)i >= self->size) {
875 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
876 return -1;
877 }
878 if (v == NULL) {
879 PyErr_SetString(PyExc_TypeError,
880 "mmap object doesn't support item deletion");
881 return -1;
882 }
883 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
884 PyErr_SetString(PyExc_IndexError,
885 "mmap assignment must be single-character string");
886 return -1;
887 }
888 if (!is_writeable(self))
889 return -1;
890 buf = PyString_AsString(v);
891 self->data[i] = buf[0];
892 return 0;
893}
894
895static int
896mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
897{
898 CHECK_VALID(-1);
899
900 if (PyIndex_Check(item)) {
901 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
902 const char *buf;
903
904 if (i == -1 && PyErr_Occurred())
905 return -1;
906 if (i < 0)
907 i += self->size;
908 if (i < 0 || (size_t)i >= self->size) {
909 PyErr_SetString(PyExc_IndexError,
910 "mmap index out of range");
911 return -1;
912 }
913 if (value == NULL) {
914 PyErr_SetString(PyExc_TypeError,
915 "mmap object doesn't support item deletion");
916 return -1;
917 }
918 if (!PyString_Check(value) || PyString_Size(value) != 1) {
919 PyErr_SetString(PyExc_IndexError,
920 "mmap assignment must be single-character string");
921 return -1;
922 }
923 if (!is_writeable(self))
924 return -1;
925 buf = PyString_AsString(value);
926 self->data[i] = buf[0];
927 return 0;
928 }
929 else if (PySlice_Check(item)) {
930 Py_ssize_t start, stop, step, slicelen;
931
932 if (PySlice_GetIndicesEx((PySliceObject *)item,
933 self->size, &start, &stop,
934 &step, &slicelen) < 0) {
935 return -1;
936 }
937 if (value == NULL) {
938 PyErr_SetString(PyExc_TypeError,
939 "mmap object doesn't support slice deletion");
940 return -1;
941 }
942 if (!PyString_Check(value)) {
943 PyErr_SetString(PyExc_IndexError,
944 "mmap slice assignment must be a string");
945 return -1;
946 }
947 if (PyString_Size(value) != slicelen) {
948 PyErr_SetString(PyExc_IndexError,
949 "mmap slice assignment is wrong size");
950 return -1;
951 }
952 if (!is_writeable(self))
953 return -1;
954
955 if (slicelen == 0)
956 return 0;
957 else if (step == 1) {
958 const char *buf = PyString_AsString(value);
959
960 if (buf == NULL)
961 return -1;
962 memcpy(self->data + start, buf, slicelen);
963 return 0;
964 }
965 else {
966 Py_ssize_t cur, i;
967 const char *buf = PyString_AsString(value);
968
969 if (buf == NULL)
970 return -1;
971 for (cur = start, i = 0; i < slicelen;
972 cur += step, i++) {
973 self->data[cur] = buf[i];
974 }
975 return 0;
976 }
977 }
978 else {
979 PyErr_SetString(PyExc_TypeError,
980 "mmap indices must be integer");
981 return -1;
982 }
983}
984
985static PySequenceMethods mmap_as_sequence = {
986 (lenfunc)mmap_length, /*sq_length*/
987 (binaryfunc)mmap_concat, /*sq_concat*/
988 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
989 (ssizeargfunc)mmap_item, /*sq_item*/
990 (ssizessizeargfunc)mmap_slice, /*sq_slice*/
991 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
992 (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/
993};
994
995static PyMappingMethods mmap_as_mapping = {
996 (lenfunc)mmap_length,
997 (binaryfunc)mmap_subscript,
998 (objobjargproc)mmap_ass_subscript,
999};
1000
1001static PyBufferProcs mmap_as_buffer = {
1002 (readbufferproc)mmap_buffer_getreadbuf,
1003 (writebufferproc)mmap_buffer_getwritebuf,
1004 (segcountproc)mmap_buffer_getsegcount,
1005 (charbufferproc)mmap_buffer_getcharbuffer,
1006};
1007
1008static PyObject *
1009new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1010
1011PyDoc_STRVAR(mmap_doc,
1012"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1013\n\
1014Maps length bytes from the file specified by the file handle fileno,\n\
1015and returns a mmap object. If length is larger than the current size\n\
1016of the file, the file is extended to contain length bytes. If length\n\
1017is 0, the maximum length of the map is the current size of the file,\n\
1018except that if the file is empty Windows raises an exception (you cannot\n\
1019create an empty mapping on Windows).\n\
1020\n\
1021Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1022\n\
1023Maps length bytes from the file specified by the file descriptor fileno,\n\
1024and returns a mmap object. If length is 0, the maximum length of the map\n\
1025will be the current size of the file when mmap is called.\n\
1026flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1027private copy-on-write mapping, so changes to the contents of the mmap\n\
1028object will be private to this process, and MAP_SHARED creates a mapping\n\
1029that's shared with all other processes mapping the same areas of the file.\n\
1030The default value is MAP_SHARED.\n\
1031\n\
1032To map anonymous memory, pass -1 as the fileno (both versions).");
1033
1034
1035static PyTypeObject mmap_object_type = {
1036 PyVarObject_HEAD_INIT(NULL, 0)
1037 "mmap.mmap", /* tp_name */
1038 sizeof(mmap_object), /* tp_size */
1039 0, /* tp_itemsize */
1040 /* methods */
1041 (destructor) mmap_object_dealloc, /* tp_dealloc */
1042 0, /* tp_print */
1043 0, /* tp_getattr */
1044 0, /* tp_setattr */
1045 0, /* tp_compare */
1046 0, /* tp_repr */
1047 0, /* tp_as_number */
1048 &mmap_as_sequence, /*tp_as_sequence*/
1049 &mmap_as_mapping, /*tp_as_mapping*/
1050 0, /*tp_hash*/
1051 0, /*tp_call*/
1052 0, /*tp_str*/
1053 PyObject_GenericGetAttr, /*tp_getattro*/
1054 0, /*tp_setattro*/
1055 &mmap_as_buffer, /*tp_as_buffer*/
1056 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
1057 mmap_doc, /*tp_doc*/
1058 0, /* tp_traverse */
1059 0, /* tp_clear */
1060 0, /* tp_richcompare */
1061 0, /* tp_weaklistoffset */
1062 0, /* tp_iter */
1063 0, /* tp_iternext */
1064 mmap_object_methods, /* tp_methods */
1065 0, /* tp_members */
1066 0, /* tp_getset */
1067 0, /* tp_base */
1068 0, /* tp_dict */
1069 0, /* tp_descr_get */
1070 0, /* tp_descr_set */
1071 0, /* tp_dictoffset */
1072 0, /* tp_init */
1073 PyType_GenericAlloc, /* tp_alloc */
1074 new_mmap_object, /* tp_new */
1075 PyObject_Del, /* tp_free */
1076};
1077
1078
1079/* extract the map size from the given PyObject
1080
1081 Returns -1 on error, with an appropriate Python exception raised. On
1082 success, the map size is returned. */
1083static Py_ssize_t
1084_GetMapSize(PyObject *o, const char* param)
1085{
1086 if (o == NULL)
1087 return 0;
1088 if (PyIndex_Check(o)) {
1089 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1090 if (i==-1 && PyErr_Occurred())
1091 return -1;
1092 if (i < 0) {
1093 PyErr_Format(PyExc_OverflowError,
1094 "memory mapped %s must be positive",
1095 param);
1096 return -1;
1097 }
1098 return i;
1099 }
1100
1101 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1102 return -1;
1103}
1104
1105#ifdef UNIX
1106#ifdef HAVE_LARGEFILE_SUPPORT
1107#define _Py_PARSE_OFF_T "L"
1108#else
1109#define _Py_PARSE_OFF_T "l"
1110#endif
1111
1112static PyObject *
1113new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
1114{
1115#ifdef HAVE_FSTAT
1116 struct stat st;
1117#endif
1118 mmap_object *m_obj;
1119 PyObject *map_size_obj = NULL;
1120 Py_ssize_t map_size;
1121 off_t offset = 0;
1122 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1123 int devzero = -1;
1124 int access = (int)ACCESS_DEFAULT;
1125 static char *keywords[] = {"fileno", "length",
1126 "flags", "prot",
1127 "access", "offset", NULL};
1128
1129 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
1130 &fd, &map_size_obj, &flags, &prot,
1131 &access, &offset))
1132 return NULL;
1133 map_size = _GetMapSize(map_size_obj, "size");
1134 if (map_size < 0)
1135 return NULL;
1136 if (offset < 0) {
1137 PyErr_SetString(PyExc_OverflowError,
1138 "memory mapped offset must be positive");
1139 return NULL;
1140 }
1141
1142 if ((access != (int)ACCESS_DEFAULT) &&
1143 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1144 return PyErr_Format(PyExc_ValueError,
1145 "mmap can't specify both access and flags, prot.");
1146 switch ((access_mode)access) {
1147 case ACCESS_READ:
1148 flags = MAP_SHARED;
1149 prot = PROT_READ;
1150 break;
1151 case ACCESS_WRITE:
1152 flags = MAP_SHARED;
1153 prot = PROT_READ | PROT_WRITE;
1154 break;
1155 case ACCESS_COPY:
1156 flags = MAP_PRIVATE;
1157 prot = PROT_READ | PROT_WRITE;
1158 break;
1159 case ACCESS_DEFAULT:
1160 /* map prot to access type */
1161 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1162 /* ACCESS_DEFAULT */
1163 }
1164 else if (prot & PROT_WRITE) {
1165 access = ACCESS_WRITE;
1166 }
1167 else {
1168 access = ACCESS_READ;
1169 }
1170 break;
1171 default:
1172 return PyErr_Format(PyExc_ValueError,
1173 "mmap invalid access parameter.");
1174 }
1175
1176#ifdef __APPLE__
1177 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1178 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1179 if (fd != -1)
1180 (void)fcntl(fd, F_FULLFSYNC);
1181#endif
1182#ifdef HAVE_FSTAT
1183# ifdef __VMS
1184 /* on OpenVMS we must ensure that all bytes are written to the file */
1185 if (fd != -1) {
1186 fsync(fd);
1187 }
1188# endif
1189 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1190 if (map_size == 0) {
1191 if (st.st_size == 0) {
1192 PyErr_SetString(PyExc_ValueError,
1193 "cannot mmap an empty file");
1194 return NULL;
1195 }
1196 if (offset >= st.st_size) {
1197 PyErr_SetString(PyExc_ValueError,
1198 "mmap offset is greater than file size");
1199 return NULL;
1200 }
1201 if (st.st_size - offset > PY_SSIZE_T_MAX) {
1202 PyErr_SetString(PyExc_ValueError,
1203 "mmap length is too large");
1204 return NULL;
1205 }
1206 map_size = (Py_ssize_t) (st.st_size - offset);
1207 } else if (offset + (size_t)map_size > st.st_size) {
1208 PyErr_SetString(PyExc_ValueError,
1209 "mmap length is greater than file size");
1210 return NULL;
1211 }
1212 }
1213#endif
1214 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1215 if (m_obj == NULL) {return NULL;}
1216 m_obj->data = NULL;
1217 m_obj->size = (size_t) map_size;
1218 m_obj->pos = (size_t) 0;
1219 m_obj->offset = offset;
1220 if (fd == -1) {
1221 m_obj->fd = -1;
1222 /* Assume the caller wants to map anonymous memory.
1223 This is the same behaviour as Windows. mmap.mmap(-1, size)
1224 on both Windows and Unix map anonymous memory.
1225 */
1226#ifdef MAP_ANONYMOUS
1227 /* BSD way to map anonymous memory */
1228 flags |= MAP_ANONYMOUS;
1229#else
1230 /* SVR4 method to map anonymous memory is to open /dev/zero */
1231 fd = devzero = open("/dev/zero", O_RDWR);
1232 if (devzero == -1) {
1233 Py_DECREF(m_obj);
1234 PyErr_SetFromErrno(mmap_module_error);
1235 return NULL;
1236 }
1237#endif
1238 } else {
1239 m_obj->fd = dup(fd);
1240 if (m_obj->fd == -1) {
1241 Py_DECREF(m_obj);
1242 PyErr_SetFromErrno(mmap_module_error);
1243 return NULL;
1244 }
1245 }
1246
1247 m_obj->data = mmap(NULL, map_size,
1248 prot, flags,
1249 fd, offset);
1250
1251 if (devzero != -1) {
1252 close(devzero);
1253 }
1254
1255 if (m_obj->data == (char *)-1) {
1256 m_obj->data = NULL;
1257 Py_DECREF(m_obj);
1258 PyErr_SetFromErrno(mmap_module_error);
1259 return NULL;
1260 }
1261 m_obj->access = (access_mode)access;
1262 return (PyObject *)m_obj;
1263}
1264#endif /* UNIX */
1265
1266#ifdef MS_WINDOWS
1267
1268/* A note on sizes and offsets: while the actual map size must hold in a
1269 Py_ssize_t, both the total file size and the start offset can be longer
1270 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1271*/
1272
1273static PyObject *
1274new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
1275{
1276 mmap_object *m_obj;
1277 PyObject *map_size_obj = NULL;
1278 Py_ssize_t map_size;
1279 PY_LONG_LONG offset = 0, size;
1280 DWORD off_hi; /* upper 32 bits of offset */
1281 DWORD off_lo; /* lower 32 bits of offset */
1282 DWORD size_hi; /* upper 32 bits of size */
1283 DWORD size_lo; /* lower 32 bits of size */
1284 char *tagname = "";
1285 DWORD dwErr = 0;
1286 int fileno;
1287 HANDLE fh = 0;
1288 int access = (access_mode)ACCESS_DEFAULT;
1289 DWORD flProtect, dwDesiredAccess;
1290 static char *keywords[] = { "fileno", "length",
1291 "tagname",
1292 "access", "offset", NULL };
1293
1294 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
1295 &fileno, &map_size_obj,
1296 &tagname, &access, &offset)) {
1297 return NULL;
1298 }
1299
1300 switch((access_mode)access) {
1301 case ACCESS_READ:
1302 flProtect = PAGE_READONLY;
1303 dwDesiredAccess = FILE_MAP_READ;
1304 break;
1305 case ACCESS_DEFAULT: case ACCESS_WRITE:
1306 flProtect = PAGE_READWRITE;
1307 dwDesiredAccess = FILE_MAP_WRITE;
1308 break;
1309 case ACCESS_COPY:
1310 flProtect = PAGE_WRITECOPY;
1311 dwDesiredAccess = FILE_MAP_COPY;
1312 break;
1313 default:
1314 return PyErr_Format(PyExc_ValueError,
1315 "mmap invalid access parameter.");
1316 }
1317
1318 map_size = _GetMapSize(map_size_obj, "size");
1319 if (map_size < 0)
1320 return NULL;
1321 if (offset < 0) {
1322 PyErr_SetString(PyExc_OverflowError,
1323 "memory mapped offset must be positive");
1324 return NULL;
1325 }
1326
1327 /* assume -1 and 0 both mean invalid filedescriptor
1328 to 'anonymously' map memory.
1329 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1330 XXX: Should this code be added?
1331 if (fileno == 0)
1332 PyErr_Warn(PyExc_DeprecationWarning,
1333 "don't use 0 for anonymous memory");
1334 */
1335 if (fileno != -1 && fileno != 0) {
1336 /* Ensure that fileno is within the CRT's valid range */
1337 if (_PyVerify_fd(fileno) == 0) {
1338 PyErr_SetFromErrno(mmap_module_error);
1339 return NULL;
1340 }
1341 fh = (HANDLE)_get_osfhandle(fileno);
1342 if (fh==(HANDLE)-1) {
1343 PyErr_SetFromErrno(mmap_module_error);
1344 return NULL;
1345 }
1346 /* Win9x appears to need us seeked to zero */
1347 lseek(fileno, 0, SEEK_SET);
1348 }
1349
1350 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1351 if (m_obj == NULL)
1352 return NULL;
1353 /* Set every field to an invalid marker, so we can safely
1354 destruct the object in the face of failure */
1355 m_obj->data = NULL;
1356 m_obj->file_handle = INVALID_HANDLE_VALUE;
1357 m_obj->map_handle = NULL;
1358 m_obj->tagname = NULL;
1359 m_obj->offset = offset;
1360
1361 if (fh) {
1362 /* It is necessary to duplicate the handle, so the
1363 Python code can close it on us */
1364 if (!DuplicateHandle(
1365 GetCurrentProcess(), /* source process handle */
1366 fh, /* handle to be duplicated */
1367 GetCurrentProcess(), /* target proc handle */
1368 (LPHANDLE)&m_obj->file_handle, /* result */
1369 0, /* access - ignored due to options value */
1370 FALSE, /* inherited by child processes? */
1371 DUPLICATE_SAME_ACCESS)) { /* options */
1372 dwErr = GetLastError();
1373 Py_DECREF(m_obj);
1374 PyErr_SetFromWindowsErr(dwErr);
1375 return NULL;
1376 }
1377 if (!map_size) {
1378 DWORD low,high;
1379 low = GetFileSize(fh, &high);
1380 /* low might just happen to have the value INVALID_FILE_SIZE;
1381 so we need to check the last error also. */
1382 if (low == INVALID_FILE_SIZE &&
1383 (dwErr = GetLastError()) != NO_ERROR) {
1384 Py_DECREF(m_obj);
1385 return PyErr_SetFromWindowsErr(dwErr);
1386 }
1387
1388 size = (((PY_LONG_LONG) high) << 32) + low;
1389 if (size == 0) {
1390 PyErr_SetString(PyExc_ValueError,
1391 "cannot mmap an empty file");
1392 Py_DECREF(m_obj);
1393 return NULL;
1394 }
1395 if (offset >= size) {
1396 PyErr_SetString(PyExc_ValueError,
1397 "mmap offset is greater than file size");
1398 Py_DECREF(m_obj);
1399 return NULL;
1400 }
1401 if (size - offset > PY_SSIZE_T_MAX) {
1402 PyErr_SetString(PyExc_ValueError,
1403 "mmap length is too large");
1404 Py_DECREF(m_obj);
1405 return NULL;
1406 }
1407 m_obj->size = (Py_ssize_t) (size - offset);
1408 } else {
1409 m_obj->size = map_size;
1410 size = offset + map_size;
1411 }
1412 }
1413 else {
1414 m_obj->size = map_size;
1415 size = offset + map_size;
1416 }
1417
1418 /* set the initial position */
1419 m_obj->pos = (size_t) 0;
1420
1421 /* set the tag name */
1422 if (tagname != NULL && *tagname != '\0') {
1423 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1424 if (m_obj->tagname == NULL) {
1425 PyErr_NoMemory();
1426 Py_DECREF(m_obj);
1427 return NULL;
1428 }
1429 strcpy(m_obj->tagname, tagname);
1430 }
1431 else
1432 m_obj->tagname = NULL;
1433
1434 m_obj->access = (access_mode)access;
1435 size_hi = (DWORD)(size >> 32);
1436 size_lo = (DWORD)(size & 0xFFFFFFFF);
1437 off_hi = (DWORD)(offset >> 32);
1438 off_lo = (DWORD)(offset & 0xFFFFFFFF);
1439 /* For files, it would be sufficient to pass 0 as size.
1440 For anonymous maps, we have to pass the size explicitly. */
1441 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1442 NULL,
1443 flProtect,
1444 size_hi,
1445 size_lo,
1446 m_obj->tagname);
1447 if (m_obj->map_handle != NULL) {
1448 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1449 dwDesiredAccess,
1450 off_hi,
1451 off_lo,
1452 m_obj->size);
1453 if (m_obj->data != NULL)
1454 return (PyObject *)m_obj;
1455 else {
1456 dwErr = GetLastError();
1457 CloseHandle(m_obj->map_handle);
1458 m_obj->map_handle = NULL;
1459 }
1460 } else
1461 dwErr = GetLastError();
1462 Py_DECREF(m_obj);
1463 PyErr_SetFromWindowsErr(dwErr);
1464 return NULL;
1465}
1466#endif /* MS_WINDOWS */
1467
1468static void
1469setint(PyObject *d, const char *name, long value)
1470{
1471 PyObject *o = PyInt_FromLong(value);
1472 if (o && PyDict_SetItemString(d, name, o) == 0) {
1473 Py_DECREF(o);
1474 }
1475}
1476
1477PyMODINIT_FUNC
1478initmmap(void)
1479{
1480 PyObject *dict, *module;
1481
1482 if (PyType_Ready(&mmap_object_type) < 0)
1483 return;
1484
1485 module = Py_InitModule("mmap", NULL);
1486 if (module == NULL)
1487 return;
1488 dict = PyModule_GetDict(module);
1489 if (!dict)
1490 return;
1491 mmap_module_error = PyErr_NewException("mmap.error",
1492 PyExc_EnvironmentError , NULL);
1493 if (mmap_module_error == NULL)
1494 return;
1495 PyDict_SetItemString(dict, "error", mmap_module_error);
1496 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
1497#ifdef PROT_EXEC
1498 setint(dict, "PROT_EXEC", PROT_EXEC);
1499#endif
1500#ifdef PROT_READ
1501 setint(dict, "PROT_READ", PROT_READ);
1502#endif
1503#ifdef PROT_WRITE
1504 setint(dict, "PROT_WRITE", PROT_WRITE);
1505#endif
1506
1507#ifdef MAP_SHARED
1508 setint(dict, "MAP_SHARED", MAP_SHARED);
1509#endif
1510#ifdef MAP_PRIVATE
1511 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
1512#endif
1513#ifdef MAP_DENYWRITE
1514 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
1515#endif
1516#ifdef MAP_EXECUTABLE
1517 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
1518#endif
1519#ifdef MAP_ANONYMOUS
1520 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1521 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
1522#endif
1523
1524 setint(dict, "PAGESIZE", (long)my_getpagesize());
1525
1526 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
1527
1528 setint(dict, "ACCESS_READ", ACCESS_READ);
1529 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1530 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1531}
Note: See TracBrowser for help on using the repository browser.