mmapmodule.c 33.6 KB
Newer Older
1 2
/*
 /  Author: Sam Rushing <rushing@nightmare.com>
3
 /  Hacked for Unix by AMK
4
 /  $Id$
5

6 7 8
 / Modified to support mmap with offset - to map a 'window' of a file
 /   Author:  Yotam Medini  yotamm@mellanox.co.il
 /
9 10 11 12 13 14
 / mmapmodule.cpp -- map a view of a file into memory
 /
 / todo: need permission flags, perhaps a 'chsize' analog
 /   not all functions check range yet!!!
 /
 /
Mark Hammond's avatar
Mark Hammond committed
15 16 17
 / This version of mmapmodule.c has been changed significantly
 / from the original mmapfile.c on which it was based.
 / The original version of mmapfile is maintained by Sam at
18 19 20
 / ftp://squirl.nightmare.com/pub/python/python-ext.
*/

21
#define PY_SSIZE_T_CLEAN
22 23
#include <Python.h>

24
#ifndef MS_WINDOWS
25 26 27
#define UNIX
#endif

28
#ifdef MS_WINDOWS
29
#include <windows.h>
30 31 32
static int
my_getpagesize(void)
{
33 34 35
	SYSTEM_INFO si;
	GetSystemInfo(&si);
	return si.dwPageSize;
36
}
37 38 39 40 41 42 43 44 45 46

static int
my_getallocationgranularity (void)
{

	SYSTEM_INFO si;
	GetSystemInfo(&si);
	return si.dwAllocationGranularity;
}

47 48 49 50
#endif

#ifdef UNIX
#include <sys/mman.h>
51
#include <sys/stat.h>
52

53 54 55 56
#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
static int
my_getpagesize(void)
{
57
	return sysconf(_SC_PAGESIZE);
58
}
59 60

#define my_getallocationgranularity my_getpagesize
61 62 63 64
#else
#define my_getpagesize getpagesize
#endif

65 66
#endif /* UNIX */

67
#include <string.h>
68 69

#ifdef HAVE_SYS_TYPES_H
70
#include <sys/types.h>
71
#endif /* HAVE_SYS_TYPES_H */
72

73
/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
74 75 76 77
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
#  define MAP_ANONYMOUS MAP_ANON
#endif

78 79
static PyObject *mmap_module_error;

80 81 82 83 84 85 86 87
typedef enum
{
	ACCESS_DEFAULT,
	ACCESS_READ,
	ACCESS_WRITE,
	ACCESS_COPY
} access_mode;

88
typedef struct {
89 90 91
	PyObject_HEAD
	char *	data;
	size_t	size;
92 93
	size_t	pos;    /* relative to offset */
	size_t	offset; 
94
        int     exports;
95

96
#ifdef MS_WINDOWS
97
	HANDLE	map_handle;
Mark Hammond's avatar
Mark Hammond committed
98
	HANDLE	file_handle;
99
	char *	tagname;
100 101 102
#endif

#ifdef UNIX
103
        int fd;
104
#endif
105 106

        access_mode access;
107 108
} mmap_object;

109

110
static void
Fredrik Lundh's avatar
Fredrik Lundh committed
111
mmap_object_dealloc(mmap_object *m_obj)
112
{
113
#ifdef MS_WINDOWS
114 115 116 117
	if (m_obj->data != NULL)
		UnmapViewOfFile (m_obj->data);
	if (m_obj->map_handle != INVALID_HANDLE_VALUE)
		CloseHandle (m_obj->map_handle);
Mark Hammond's avatar
Mark Hammond committed
118 119
	if (m_obj->file_handle != INVALID_HANDLE_VALUE)
		CloseHandle (m_obj->file_handle);
120 121
	if (m_obj->tagname)
		PyMem_Free(m_obj->tagname);
122
#endif /* MS_WINDOWS */
123 124

#ifdef UNIX
125 126
	if (m_obj->fd >= 0)
		(void) close(m_obj->fd);
127
	if (m_obj->data!=NULL) {
128
		msync(m_obj->data, m_obj->size, MS_SYNC);
129 130
		munmap(m_obj->data, m_obj->size);
	}
131 132
#endif /* UNIX */

133
	Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
134 135 136
}

static PyObject *
137
mmap_close_method(mmap_object *self, PyObject *unused)
138
{
139 140 141 142 143
        if (self->exports > 0) {
                PyErr_SetString(PyExc_BufferError, "cannot close "\
                                "exported pointers exist");
                return NULL;
        }
144
#ifdef MS_WINDOWS
Mark Hammond's avatar
Mark Hammond committed
145
	/* For each resource we maintain, we need to check
146
	   the value is valid, and if so, free the resource
Mark Hammond's avatar
Mark Hammond committed
147 148 149 150 151 152
	   and set the member value to an invalid value so
	   the dealloc does not attempt to resource clearing
	   again.
	   TODO - should we check for errors in the close operations???
	*/
	if (self->data != NULL) {
153
		UnmapViewOfFile(self->data);
Mark Hammond's avatar
Mark Hammond committed
154 155 156
		self->data = NULL;
	}
	if (self->map_handle != INVALID_HANDLE_VALUE) {
157
		CloseHandle(self->map_handle);
Mark Hammond's avatar
Mark Hammond committed
158 159 160
		self->map_handle = INVALID_HANDLE_VALUE;
	}
	if (self->file_handle != INVALID_HANDLE_VALUE) {
161
		CloseHandle(self->file_handle);
Mark Hammond's avatar
Mark Hammond committed
162 163
		self->file_handle = INVALID_HANDLE_VALUE;
	}
164
#endif /* MS_WINDOWS */
165 166

#ifdef UNIX
167 168
	(void) close(self->fd);
	self->fd = -1;
169 170 171 172
	if (self->data != NULL) {
		munmap(self->data, self->size);
		self->data = NULL;
	}
173 174
#endif

175
	Py_INCREF(Py_None);
176
	return Py_None;
177 178
}

179
#ifdef MS_WINDOWS
180 181
#define CHECK_VALID(err)						\
do {									\
182
    if (self->map_handle == INVALID_HANDLE_VALUE) {						\
183
	PyErr_SetString(PyExc_ValueError, "mmap closed or invalid");	\
184 185
	return err;							\
    }									\
186
} while (0)
187
#endif /* MS_WINDOWS */
188 189

#ifdef UNIX
190 191 192
#define CHECK_VALID(err)						\
do {									\
    if (self->data == NULL) {						\
193
	PyErr_SetString(PyExc_ValueError, "mmap closed or invalid");	\
194 195
	return err;							\
	}								\
196 197 198 199
} while (0)
#endif /* UNIX */

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
200
mmap_read_byte_method(mmap_object *self,
201
		      PyObject *unused)
202
{
203
	CHECK_VALID(NULL);
204
	if (self->pos < self->size) {
Tim Peters's avatar
Tim Peters committed
205
	        char value = self->data[self->pos];
206
		self->pos += 1;
Tim Peters's avatar
Tim Peters committed
207
		return Py_BuildValue("c", value);
208
	} else {
209
		PyErr_SetString(PyExc_ValueError, "read byte out of range");
210 211
		return NULL;
	}
212 213 214
}

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
215
mmap_read_line_method(mmap_object *self,
216
		      PyObject *unused)
217
{
Fredrik Lundh's avatar
Fredrik Lundh committed
218 219 220 221
	char *start = self->data+self->pos;
	char *eof = self->data+self->size;
	char *eol;
	PyObject *result;
222 223 224

	CHECK_VALID(NULL);

225 226 227 228 229 230
	eol = memchr(start, '\n', self->size - self->pos);
	if (!eol)
		eol = eof;
	else
		++eol;		/* we're interested in the position after the
				   newline. */
231
	result = PyByteArray_FromStringAndSize(start, (eol - start));
232
	self->pos += (eol - start);
233
	return result;
234 235 236
}

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
237 238
mmap_read_method(mmap_object *self,
		 PyObject *args)
239
{
240
	Py_ssize_t num_bytes;
241 242 243
	PyObject *result;

	CHECK_VALID(NULL);
244
	if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
245 246 247 248 249 250
		return(NULL);

	/* silently 'adjust' out-of-range requests */
	if ((self->pos + num_bytes) > self->size) {
		num_bytes -= (self->pos+num_bytes) - self->size;
	}
251
	result = PyByteArray_FromStringAndSize(self->data+self->pos, num_bytes);
252
	self->pos += num_bytes;
253
	return result;
254 255 256
}

static PyObject *
257 258 259
mmap_gfind(mmap_object *self,
	   PyObject *args,
	   int reverse)
260
{
261
	Py_ssize_t start = self->pos;
262 263
	Py_ssize_t end = self->size;
	const char *needle;
264
	Py_ssize_t len;
265

266
	CHECK_VALID(NULL);
267 268
	if (!PyArg_ParseTuple(args, reverse ? "s#|nn:rfind" : "s#|nn:find",
			      &needle, &len, &start, &end)) {
269 270
		return NULL;
	} else {
271 272
		const char *p, *start_p, *end_p;
		int sign = reverse ? -1 : 1;
273 274

                if (start < 0)
275
			start += self->size;
276
                if (start < 0)
277
			start = 0;
278
                else if ((size_t)start > self->size)
279
			start = self->size;
280

281 282 283 284 285 286 287
                if (end < 0)
			end += self->size;
		if (end < 0)
			end = 0;
		else if ((size_t)end > self->size)
			end = self->size;

288 289
		start_p = self->data + start;
		end_p = self->data + end;
290

291 292
		for (p = (reverse ? end_p - len : start_p);
		     (p >= start_p) && (p + len <= end_p); p += sign) {
293
			Py_ssize_t i;
294 295 296
			for (i = 0; i < len && needle[i] == p[i]; ++i)
				/* nothing */;
			if (i == len) {
297
				return PyLong_FromSsize_t(p - self->data);
298
			}
299
		}
300
		return PyLong_FromLong(-1);
301
	}
302 303
}

304 305 306 307 308 309 310 311 312 313 314 315 316 317
static PyObject *
mmap_find_method(mmap_object *self,
		 PyObject *args)
{
	return mmap_gfind(self, args, 0);
}

static PyObject *
mmap_rfind_method(mmap_object *self,
		 PyObject *args)
{
	return mmap_gfind(self, args, 1);
}

318
static int
319
is_writable(mmap_object *self)
320 321
{
	if (self->access != ACCESS_READ)
322
		return 1;
323 324 325 326
	PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
	return 0;
}

327
static int
328 329
is_resizeable(mmap_object *self)
{
330 331 332 333 334
        if (self->exports > 0) {
                PyErr_SetString(PyExc_BufferError,
                                "mmap can't resize with extant buffers exported.");
                return 0;
        }
335
	if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
336
		return 1;
337
	PyErr_Format(PyExc_TypeError,
338 339 340 341 342
		     "mmap can't resize a readonly or copy-on-write memory map.");
	return 0;
}


343
static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
344 345
mmap_write_method(mmap_object *self,
		  PyObject *args)
346
{
347
	Py_ssize_t length;
Fredrik Lundh's avatar
Fredrik Lundh committed
348
	char *data;
349

350
	CHECK_VALID(NULL);
351
	if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
352
		return(NULL);
353

354
	if (!is_writable(self))
355 356
		return NULL;

357
	if ((self->pos + length) > self->size) {
358
		PyErr_SetString(PyExc_ValueError, "data out of range");
359 360
		return NULL;
	}
361
	memcpy(self->data+self->pos, data, length);
362
	self->pos = self->pos+length;
363
	Py_INCREF(Py_None);
364
	return Py_None;
365 366 367
}

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
368 369
mmap_write_byte_method(mmap_object *self,
		       PyObject *args)
370
{
371
	char value;
372

373
	CHECK_VALID(NULL);
374
	if (!PyArg_ParseTuple(args, "c:write_byte", &value))
375
		return(NULL);
376

377
	if (!is_writable(self))
378
		return NULL;
379 380
	*(self->data+self->pos) = value;
	self->pos += 1;
381
	Py_INCREF(Py_None);
382
	return Py_None;
383
}
384

385
static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
386
mmap_size_method(mmap_object *self,
387
		 PyObject *unused)
388
{
389
	CHECK_VALID(NULL);
390

391
#ifdef MS_WINDOWS
Mark Hammond's avatar
Mark Hammond committed
392
	if (self->file_handle != INVALID_HANDLE_VALUE) {
393 394 395 396 397 398 399 400 401 402 403
		DWORD low,high;
		PY_LONG_LONG size;
		low = GetFileSize(self->file_handle, &high);
		if (low == INVALID_FILE_SIZE) {
			/* It might be that the function appears to have failed,
			   when indeed its size equals INVALID_FILE_SIZE */
			DWORD error = GetLastError();
			if (error != NO_ERROR)
				return PyErr_SetFromWindowsErr(error);
		}
		if (!high && low < LONG_MAX)
404
			return PyLong_FromLong((long)low);
405 406
		size = (((PY_LONG_LONG)high)<<32) + low;
		return PyLong_FromLongLong(size);
407
	} else {
408
		return PyLong_FromSsize_t(self->size);
409
	}
410
#endif /* MS_WINDOWS */
411 412

#ifdef UNIX
413 414 415 416 417 418
	{
		struct stat buf;
		if (-1 == fstat(self->fd, &buf)) {
			PyErr_SetFromErrno(mmap_module_error);
			return NULL;
		}
419
		return PyLong_FromSsize_t(buf.st_size);
420
	}
421 422 423 424 425 426 427 428 429 430 431 432 433
#endif /* UNIX */
}

/* This assumes that you want the entire file mapped,
 / and when recreating the map will make the new file
 / have the new size
 /
 / Is this really necessary?  This could easily be done
 / from python by just closing and re-opening with the
 / new size?
 */

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
434 435
mmap_resize_method(mmap_object *self,
		   PyObject *args)
436
{
437
	Py_ssize_t new_size;
438
	CHECK_VALID(NULL);
439
	if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
440
	    !is_resizeable(self)) {
441
		return NULL;
442
#ifdef MS_WINDOWS
443
	} else {
444
		DWORD dwErrCode = 0;
445
		DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
446
		/* First, unmap the file view */
447
		UnmapViewOfFile(self->data);
448
		/* Close the mapping object */
449
		CloseHandle(self->map_handle);
450
		/* Move to the desired EOF position */
451
#if SIZEOF_SIZE_T > 4
452 453 454 455
		newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
		newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
		off_hi = (DWORD)(self->offset >> 32);
		off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
456 457
#else
		newSizeHigh = 0;
Martin v. Löwis's avatar
Martin v. Löwis committed
458
		newSizeLow = (DWORD)new_size;
459 460
		off_hi = 0;
		off_lo = (DWORD)self->offset;
461
#endif
462
		SetFilePointer(self->file_handle,
463
			       newSizeLow, &newSizeHigh, FILE_BEGIN);
464
		/* Change the size of the file */
465
		SetEndOfFile(self->file_handle);
466
		/* Create another mapping object and remap the file view */
467
		self->map_handle = CreateFileMapping(
Mark Hammond's avatar
Mark Hammond committed
468
			self->file_handle,
469 470
			NULL,
			PAGE_READWRITE,
471 472
			0,
			0,
473 474
			self->tagname);
		if (self->map_handle != NULL) {
475 476
			self->data = (char *) MapViewOfFile(self->map_handle,
							    FILE_MAP_WRITE,
477 478 479
							    off_hi,
							    off_lo,
							    new_size);
480 481
			if (self->data != NULL) {
				self->size = new_size;
482
				Py_INCREF(Py_None);
483 484 485 486 487 488
				return Py_None;
			} else {
				dwErrCode = GetLastError();
			}
		} else {
			dwErrCode = GetLastError();
489
		}
490
		PyErr_SetFromWindowsErr(dwErrCode);
491
		return NULL;
492
#endif /* MS_WINDOWS */
493 494

#ifdef UNIX
495
#ifndef HAVE_MREMAP
496 497 498 499
	} else {
		PyErr_SetString(PyExc_SystemError,
				"mmap: resizing not available--no mremap()");
		return NULL;
500
#else
501
	} else {
Armin Rigo's avatar
Armin Rigo committed
502 503
		void *newmap;

504 505 506 507
		if (ftruncate(self->fd, new_size) == -1) {
			PyErr_SetFromErrno(mmap_module_error);
			return NULL;
		}
508

509
#ifdef MREMAP_MAYMOVE
510
		newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
511
#else
512
		newmap = mremap(self->data, self->size, new_size, 0);
513
#endif
514
		if (newmap == (void *)-1)
515 516 517 518 519 520 521 522
		{
			PyErr_SetFromErrno(mmap_module_error);
			return NULL;
		}
		self->data = newmap;
		self->size = new_size;
		Py_INCREF(Py_None);
		return Py_None;
523
#endif /* HAVE_MREMAP */
524
#endif /* UNIX */
525
	}
526 527 528
}

static PyObject *
529
mmap_tell_method(mmap_object *self, PyObject *unused)
530
{
531
	CHECK_VALID(NULL);
532
	return PyLong_FromSize_t(self->pos);
533 534 535
}

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
536
mmap_flush_method(mmap_object *self, PyObject *args)
537
{
538 539
	Py_ssize_t offset = 0;
	Py_ssize_t size = self->size;
540
	CHECK_VALID(NULL);
541
	if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
542
		return NULL;
543
	if ((size_t)(offset + size) > self->size) {
544
		PyErr_SetString(PyExc_ValueError, "flush values out of range");
545
		return NULL;
546
	}
547
#ifdef MS_WINDOWS
548 549 550 551 552 553 554
	return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
#elif defined(UNIX)
	/* XXX semantics of return value? */
	/* XXX flags for msync? */
	if (-1 == msync(self->data + offset, size, MS_SYNC)) {
		PyErr_SetFromErrno(mmap_module_error);
		return NULL;
555
	}
556 557 558 559 560
	return PyLong_FromLong(0);
#else
	PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
	return NULL;
#endif
561 562 563
}

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
564
mmap_seek_method(mmap_object *self, PyObject *args)
565
{
566
	Py_ssize_t dist;
567 568
	int how=0;
	CHECK_VALID(NULL);
569
	if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
570 571
		return NULL;
	else {
572
		size_t where;
573
		switch (how) {
574 575 576
		case 0: /* relative to start */
			if (dist < 0)
				goto onoutofrange;
577 578
			where = dist;
			break;
579
		case 1: /* relative to current position */
580
			if ((Py_ssize_t)self->pos + dist < 0)
581
				goto onoutofrange;
582 583
			where = self->pos + dist;
			break;
584
		case 2: /* relative to end */
585
			if ((Py_ssize_t)self->size + dist < 0)
586 587
				goto onoutofrange;
			where = self->size + dist;
588 589
			break;
		default:
590
			PyErr_SetString(PyExc_ValueError, "unknown seek type");
591 592
			return NULL;
		}
593 594 595
		if (where > self->size)
			goto onoutofrange;
		self->pos = where;
596
		Py_INCREF(Py_None);
597
		return Py_None;
598
	}
599

600
  onoutofrange:
601
	PyErr_SetString(PyExc_ValueError, "seek out of range");
602
	return NULL;
603 604 605
}

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
606
mmap_move_method(mmap_object *self, PyObject *args)
607
{
608 609
	unsigned long dest, src, count;
	CHECK_VALID(NULL);
610
	if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) ||
611
	    !is_writable(self)) {
612 613 614 615 616 617 618
		return NULL;
	} else {
		/* bounds check the values */
		if (/* end of source after end of data?? */
			((src+count) > self->size)
			/* dest will fit? */
			|| (dest+count > self->size)) {
619 620
			PyErr_SetString(PyExc_ValueError,
					"source or destination out of range");
621
			return NULL;
622
		} else {
623 624
			memmove(self->data+dest, self->data+src, count);
			Py_INCREF(Py_None);
625
			return Py_None;
626
		}
627
	}
628 629 630
}

static struct PyMethodDef mmap_object_methods[] = {
631
	{"close",	(PyCFunction) mmap_close_method,	METH_NOARGS},
632
	{"find",	(PyCFunction) mmap_find_method,		METH_VARARGS},
633
	{"rfind",	(PyCFunction) mmap_rfind_method,	METH_VARARGS},
634 635 636
	{"flush",	(PyCFunction) mmap_flush_method,	METH_VARARGS},
	{"move",	(PyCFunction) mmap_move_method,		METH_VARARGS},
	{"read",	(PyCFunction) mmap_read_method,		METH_VARARGS},
637 638
	{"read_byte",	(PyCFunction) mmap_read_byte_method,  	METH_NOARGS},
	{"readline",	(PyCFunction) mmap_read_line_method,	METH_NOARGS},
639 640
	{"resize",	(PyCFunction) mmap_resize_method,	METH_VARARGS},
	{"seek",	(PyCFunction) mmap_seek_method,		METH_VARARGS},
641 642
	{"size",	(PyCFunction) mmap_size_method,		METH_NOARGS},
	{"tell",	(PyCFunction) mmap_tell_method,		METH_NOARGS},
643 644
	{"write",	(PyCFunction) mmap_write_method,	METH_VARARGS},
	{"write_byte",	(PyCFunction) mmap_write_byte_method,	METH_VARARGS},
645
	{NULL,	   NULL}       /* sentinel */
646 647 648 649
};

/* Functions for treating an mmap'ed file as a buffer */

650
static int
651
mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
652
{
653
	CHECK_VALID(-1);
654
        if (PyBuffer_FillInfo(view, self->data, self->size,
655 656 657 658
                              (self->access == ACCESS_READ), flags) < 0)
                return -1;
        self->exports++;
        return 0;
659 660
}

661
static void
662
mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
663
{
664
        self->exports--;
665 666
}

Martin v. Löwis's avatar
Martin v. Löwis committed
667
static Py_ssize_t
Fredrik Lundh's avatar
Fredrik Lundh committed
668
mmap_length(mmap_object *self)
669
{
670 671
	CHECK_VALID(-1);
	return self->size;
672 673 674
}

static PyObject *
Martin v. Löwis's avatar
Martin v. Löwis committed
675
mmap_item(mmap_object *self, Py_ssize_t i)
676
{
677
	CHECK_VALID(NULL);
678
	if (i < 0 || (size_t)i >= self->size) {
679 680 681
		PyErr_SetString(PyExc_IndexError, "mmap index out of range");
		return NULL;
	}
682
	return PyByteArray_FromStringAndSize(self->data + i, 1);
683 684
}

685 686 687 688 689 690 691 692 693 694
static PyObject *
mmap_subscript(mmap_object *self, PyObject *item)
{
	CHECK_VALID(NULL);
	if (PyIndex_Check(item)) {
		Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
		if (i == -1 && PyErr_Occurred())
			return NULL;
		if (i < 0)
			i += self->size;
695
		if (i < 0 || (size_t)i > self->size) {
696 697 698 699
			PyErr_SetString(PyExc_IndexError,
				"mmap index out of range");
			return NULL;
		}
700
		return PyLong_FromLong(Py_CHARMASK(self->data[i]));
701 702 703 704 705 706 707 708
	}
	else if (PySlice_Check(item)) {
		Py_ssize_t start, stop, step, slicelen;

		if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
				 &start, &stop, &step, &slicelen) < 0) {
			return NULL;
		}
709

710
		if (slicelen <= 0)
711
			return PyBytes_FromStringAndSize("", 0);
712
		else if (step == 1)
713
			return PyBytes_FromStringAndSize(self->data + start,
714
							  slicelen);
715 716 717 718 719 720 721 722 723 724 725
		else {
			char *result_buf = (char *)PyMem_Malloc(slicelen);
			Py_ssize_t cur, i;
			PyObject *result;

			if (result_buf == NULL)
				return PyErr_NoMemory();
			for (cur = start, i = 0; i < slicelen;
			     cur += step, i++) {
			     	result_buf[i] = self->data[cur];
			}
726
			result = PyBytes_FromStringAndSize(result_buf,
727
							    slicelen);
728 729 730 731 732 733 734 735 736 737 738
			PyMem_Free(result_buf);
			return result;
		}
	}
	else {
		PyErr_SetString(PyExc_TypeError,
				"mmap indices must be integers");
		return NULL;
	}
}

739
static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
740
mmap_concat(mmap_object *self, PyObject *bb)
741
{
742 743 744 745
	CHECK_VALID(NULL);
	PyErr_SetString(PyExc_SystemError,
			"mmaps don't support concatenation");
	return NULL;
746 747 748
}

static PyObject *
Martin v. Löwis's avatar
Martin v. Löwis committed
749
mmap_repeat(mmap_object *self, Py_ssize_t n)
750
{
751 752 753 754
	CHECK_VALID(NULL);
	PyErr_SetString(PyExc_SystemError,
			"mmaps don't support repeat operation");
	return NULL;
755 756 757
}

static int
Martin v. Löwis's avatar
Martin v. Löwis committed
758
mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
759
{
760
	const char *buf;
761

762
	CHECK_VALID(-1);
763
	if (i < 0 || (size_t)i >= self->size) {
764 765 766
		PyErr_SetString(PyExc_IndexError, "mmap index out of range");
		return -1;
	}
767 768
	if (v == NULL) {
		PyErr_SetString(PyExc_TypeError,
769
				"mmap object doesn't support item deletion");
770 771
		return -1;
	}
772
	if (! (PyByteArray_Check(v) && PyByteArray_Size(v)==1) ) {
773
		PyErr_SetString(PyExc_IndexError,
774
				"mmap assignment must be length-1 bytes()");
775 776
		return -1;
	}
777
	if (!is_writable(self))
778
		return -1;
779
	buf = PyByteArray_AsString(v);
780 781
	self->data[i] = buf[0];
	return 0;
782 783
}

784 785 786 787 788
static int
mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
{
	CHECK_VALID(-1);

789 790 791
	if (!is_writable(self))
		return -1;

792 793
	if (PyIndex_Check(item)) {
		Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
794
		Py_ssize_t v;
795 796 797 798 799

		if (i == -1 && PyErr_Occurred())
			return -1;
		if (i < 0)
			i += self->size;
800
		if (i < 0 || (size_t)i > self->size) {
801
			PyErr_SetString(PyExc_IndexError,
802
					"mmap index out of range");
803 804 805 806
			return -1;
		}
		if (value == NULL) {
			PyErr_SetString(PyExc_TypeError,
807
					"mmap doesn't support item deletion");
808 809
			return -1;
		}
810 811 812
		if (!PyIndex_Check(value)) {
			PyErr_SetString(PyExc_TypeError,
					"mmap item value must be an int");
813 814
			return -1;
		}
815 816
		v = PyNumber_AsSsize_t(value, PyExc_TypeError);
		if (v == -1 && PyErr_Occurred())
817
			return -1;
818 819 820 821 822 823 824
		if (v < 0 || v > 255) {
			PyErr_SetString(PyExc_ValueError,
					"mmap item value must be "
					"in range(0, 256)");
			return -1;
		}
		self->data[i] = v;
825 826 827 828
		return 0;
	}
	else if (PySlice_Check(item)) {
		Py_ssize_t start, stop, step, slicelen;
829 830
                Py_buffer vbuf;

831 832 833 834 835 836 837 838 839 840
		if (PySlice_GetIndicesEx((PySliceObject *)item,
					 self->size, &start, &stop,
					 &step, &slicelen) < 0) {
			return -1;
		}
		if (value == NULL) {
			PyErr_SetString(PyExc_TypeError,
				"mmap object doesn't support slice deletion");
			return -1;
		}
841
                if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
842
			return -1;
843
		if (vbuf.len != slicelen) {
844 845
			PyErr_SetString(PyExc_IndexError,
				"mmap slice assignment is wrong size");
846
			PyObject_ReleaseBuffer(value, &vbuf);
847 848 849
			return -1;
		}

850 851
		if (slicelen == 0) {
		}
852
		else if (step == 1) {
853
			memcpy(self->data + start, vbuf.buf, slicelen);
854 855 856
		}
		else {
			Py_ssize_t cur, i;
857 858 859 860 861 862

			for (cur = start, i = 0;
			     i < slicelen;
			     cur += step, i++)
			{
				self->data[cur] = ((char *)vbuf.buf)[i];
863 864
			}
		}
865 866
		PyObject_ReleaseBuffer(value, &vbuf);
		return 0;
867 868 869 870 871 872 873 874
	}
	else {
		PyErr_SetString(PyExc_TypeError,
				"mmap indices must be integer");
		return -1;
	}
}

875
static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis's avatar
Martin v. Löwis committed
876
	(lenfunc)mmap_length,		       /*sq_length*/
877
	(binaryfunc)mmap_concat,	       /*sq_concat*/
Martin v. Löwis's avatar
Martin v. Löwis committed
878 879
	(ssizeargfunc)mmap_repeat,	       /*sq_repeat*/
	(ssizeargfunc)mmap_item,		       /*sq_item*/
880
	0,				      /*sq_slice*/
Martin v. Löwis's avatar
Martin v. Löwis committed
881
	(ssizeobjargproc)mmap_ass_item,	       /*sq_ass_item*/
882
	0,				      /*sq_ass_slice*/
883 884
};

885 886 887 888 889 890
static PyMappingMethods mmap_as_mapping = {
	(lenfunc)mmap_length,
	(binaryfunc)mmap_subscript,
	(objobjargproc)mmap_ass_subscript,
};

891
static PyBufferProcs mmap_as_buffer = {
892 893
        (getbufferproc)mmap_buffer_getbuf,
        (releasebufferproc)mmap_buffer_releasebuf,
894 895
};

896 897 898
static PyObject *
new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);

899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922
PyDoc_STRVAR(mmap_doc,
"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
\n\
Maps length bytes from the file specified by the file handle fileno,\n\
and returns a mmap object.  If length is larger than the current size\n\
of the file, the file is extended to contain length bytes.  If length\n\
is 0, the maximum length of the map is the current size of the file,\n\
except that if the file is empty Windows raises an exception (you cannot\n\
create an empty mapping on Windows).\n\
\n\
Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
\n\
Maps length bytes from the file specified by the file descriptor fileno,\n\
and returns a mmap object.  If length is 0, the maximum length of the map\n\
will be the current size of the file when mmap is called.\n\
flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
private copy-on-write mapping, so changes to the contents of the mmap\n\
object will be private to this process, and MAP_SHARED`creates a mapping\n\
that's shared with all other processes mapping the same areas of the file.\n\
The default value is MAP_SHARED.\n\
\n\
To map anonymous memory, pass -1 as the fileno (both versions).");


923
static PyTypeObject mmap_object_type = {
924
	PyVarObject_HEAD_INIT(NULL, 0)
925
	"mmap.mmap",				/* tp_name */
926 927 928 929 930
	sizeof(mmap_object),			/* tp_size */
	0,					/* tp_itemsize */
	/* methods */
	(destructor) mmap_object_dealloc,	/* tp_dealloc */
	0,					/* tp_print */
931
	0,					/* tp_getattr */
932 933 934 935 936
	0,					/* tp_setattr */
	0,					/* tp_compare */
	0,					/* tp_repr */
	0,					/* tp_as_number */
	&mmap_as_sequence,			/*tp_as_sequence*/
937
	&mmap_as_mapping,			/*tp_as_mapping*/
938 939 940
	0,					/*tp_hash*/
	0,					/*tp_call*/
	0,					/*tp_str*/
941
	PyObject_GenericGetAttr,		/*tp_getattro*/
942 943
	0,					/*tp_setattro*/
	&mmap_as_buffer,			/*tp_as_buffer*/
944
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,		/*tp_flags*/
945 946 947 948 949
	mmap_doc,				/*tp_doc*/
	0,					/* tp_traverse */
	0,					/* tp_clear */
	0,					/* tp_richcompare */
	0,					/* tp_weaklistoffset */
950 951
	0,		                        /* tp_iter */
	0,		                        /* tp_iternext */
952
	mmap_object_methods,			/* tp_methods */
953 954 955 956 957 958 959 960 961 962 963
	0,					/* tp_members */
	0,					/* tp_getset */
	0,					/* tp_base */
	0,					/* tp_dict */
	0,					/* tp_descr_get */
	0,					/* tp_descr_set */
	0,					/* tp_dictoffset */
	0,                                      /* tp_init */
	PyType_GenericAlloc,			/* tp_alloc */
	new_mmap_object,			/* tp_new */
	PyObject_Del,                           /* tp_free */
964 965
};

966 967 968

/* extract the map size from the given PyObject

969
   Returns -1 on error, with an appropriate Python exception raised. On
970
   success, the map size is returned. */
971
static Py_ssize_t
972
_GetMapSize(PyObject *o, const char* param)
973
{
974 975
	if (o == NULL)
		return 0;
976 977
	if (PyIndex_Check(o)) {
		Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
978
		if (i==-1 && PyErr_Occurred())
979
			return -1;
980
		if (i < 0) {
981 982 983
			PyErr_Format(PyExc_OverflowError,
					"memory mapped %s must be positive",
                                        param);
984 985
			return -1;
		}
986
		return i;
987 988
	}

989
	PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
990 991 992
	return -1;
}

993
#ifdef UNIX
994
static PyObject *
995
new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
996
{
997 998 999
#ifdef HAVE_FSTAT
	struct stat st;
#endif
Fredrik Lundh's avatar
Fredrik Lundh committed
1000
	mmap_object *m_obj;
1001 1002
	PyObject *map_size_obj = NULL, *offset_obj = NULL;
	Py_ssize_t map_size, offset;
1003
	int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1004
	int devzero = -1;
1005
	int access = (int)ACCESS_DEFAULT;
Martin v. Löwis's avatar
Martin v. Löwis committed
1006
	static char *keywords[] = {"fileno", "length",
1007
                                         "flags", "prot",
1008
                                         "access", "offset", NULL};
1009

1010
	if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
1011
					 &fd, &map_size_obj, &flags, &prot,
1012
                                         &access, &offset_obj))
1013
		return NULL;
1014
	map_size = _GetMapSize(map_size_obj, "size");
1015 1016
	if (map_size < 0)
		return NULL;
1017 1018 1019
        offset = _GetMapSize(offset_obj, "offset");
        if (offset < 0)
                return NULL;
1020

1021
	if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitz's avatar
Neal Norwitz committed
1022
	    ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1023
		return PyErr_Format(PyExc_ValueError,
1024
				    "mmap can't specify both access and flags, prot.");
Neal Norwitz's avatar
Neal Norwitz committed
1025
	switch ((access_mode)access) {
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
	case ACCESS_READ:
		flags = MAP_SHARED;
		prot = PROT_READ;
		break;
	case ACCESS_WRITE:
		flags = MAP_SHARED;
		prot = PROT_READ | PROT_WRITE;
		break;
	case ACCESS_COPY:
		flags = MAP_PRIVATE;
		prot = PROT_READ | PROT_WRITE;
		break;
1038
	case ACCESS_DEFAULT:
1039 1040 1041
		/* use the specified or default values of flags and prot */
		break;
	default:
1042
		return PyErr_Format(PyExc_ValueError,
1043 1044
				    "mmap invalid access parameter.");
	}
1045

Christian Heimes's avatar
Christian Heimes committed
1046 1047 1048 1049
    if (prot == PROT_READ) {
        access = ACCESS_READ;
    }

1050
#ifdef HAVE_FSTAT
1051 1052
#  ifdef __VMS
	/* on OpenVMS we must ensure that all bytes are written to the file */
1053 1054 1055
	if (fd != -1) {
	        fsync(fd);
	}
1056
#  endif
1057
	if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1058
		if (map_size == 0) {
1059
			map_size = st.st_size;
1060
		} else if ((size_t)offset + (size_t)map_size > st.st_size) {
1061
			PyErr_SetString(PyExc_ValueError,
1062 1063 1064
					"mmap length is greater than file size");
			return NULL;
		}
1065 1066
	}
#endif
1067
	m_obj = (mmap_object *)type->tp_alloc(type, 0);
1068
	if (m_obj == NULL) {return NULL;}
1069
	m_obj->data = NULL;
1070 1071
	m_obj->size = (size_t) map_size;
	m_obj->pos = (size_t) 0;
1072
	m_obj->exports = 0;
1073
        m_obj->offset = offset;
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
	if (fd == -1) {
		m_obj->fd = -1;
		/* Assume the caller wants to map anonymous memory.
		   This is the same behaviour as Windows.  mmap.mmap(-1, size)
		   on both Windows and Unix map anonymous memory.
		*/
#ifdef MAP_ANONYMOUS
		/* BSD way to map anonymous memory */
		flags |= MAP_ANONYMOUS;
#else
		/* SVR4 method to map anonymous memory is to open /dev/zero */
		fd = devzero = open("/dev/zero", O_RDWR);
		if (devzero == -1) {
			Py_DECREF(m_obj);
			PyErr_SetFromErrno(mmap_module_error);
			return NULL;
		}
#endif
	} else {
		m_obj->fd = dup(fd);
		if (m_obj->fd == -1) {
			Py_DECREF(m_obj);
			PyErr_SetFromErrno(mmap_module_error);
			return NULL;
		}
1099
	}
1100
	
1101
	m_obj->data = mmap(NULL, map_size,
1102
			   prot, flags,
1103
			   fd, offset);
1104 1105 1106 1107 1108

	if (devzero != -1) {
		close(devzero);
	}

1109
	if (m_obj->data == (char *)-1) {
1110
	        m_obj->data = NULL;
1111 1112 1113 1114
		Py_DECREF(m_obj);
		PyErr_SetFromErrno(mmap_module_error);
		return NULL;
	}
1115
	m_obj->access = (access_mode)access;
1116
	return (PyObject *)m_obj;
1117 1118 1119
}
#endif /* UNIX */

1120
#ifdef MS_WINDOWS
1121
static PyObject *
1122
new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
1123
{
Fredrik Lundh's avatar
Fredrik Lundh committed
1124
	mmap_object *m_obj;
1125 1126 1127 1128 1129 1130
	PyObject *map_size_obj = NULL, *offset_obj = NULL;
	Py_ssize_t map_size, offset;
	DWORD off_hi;	/* upper 32 bits of offset */
	DWORD off_lo;	/* lower 32 bits of offset */
	DWORD size_hi;	/* upper 32 bits of size */
	DWORD size_lo;	/* lower 32 bits of size */
Fredrik Lundh's avatar
Fredrik Lundh committed
1131
	char *tagname = "";
1132 1133
	DWORD dwErr = 0;
	int fileno;
Mark Hammond's avatar
Mark Hammond committed
1134
	HANDLE fh = 0;
1135
	int access = (access_mode)ACCESS_DEFAULT;
1136
	DWORD flProtect, dwDesiredAccess;
Martin v. Löwis's avatar
Martin v. Löwis committed
1137
	static char *keywords[] = { "fileno", "length",
1138
                                          "tagname",
1139
                                          "access", "offset", NULL };
1140

1141
	if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
1142
					 &fileno, &map_size_obj,
1143
					 &tagname, &access, &offset_obj)) {
1144
		return NULL;
1145 1146
	}

1147
	switch((access_mode)access) {
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160
	case ACCESS_READ:
		flProtect = PAGE_READONLY;
		dwDesiredAccess = FILE_MAP_READ;
		break;
	case ACCESS_DEFAULT:  case ACCESS_WRITE:
		flProtect = PAGE_READWRITE;
		dwDesiredAccess = FILE_MAP_WRITE;
		break;
	case ACCESS_COPY:
		flProtect = PAGE_WRITECOPY;
		dwDesiredAccess = FILE_MAP_COPY;
		break;
	default:
1161
		return PyErr_Format(PyExc_ValueError,
1162 1163 1164
				    "mmap invalid access parameter.");
	}

1165
	map_size = _GetMapSize(map_size_obj, "size");
1166 1167
	if (map_size < 0)
		return NULL;
1168 1169 1170
        offset = _GetMapSize(offset_obj, "offset");
        if (offset < 0)
                return NULL;
1171

1172 1173 1174 1175 1176
	/* assume -1 and 0 both mean invalid filedescriptor
	   to 'anonymously' map memory.
	   XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
	   XXX: Should this code be added?
	   if (fileno == 0)
1177 1178 1179
	   	PyErr_WarnEx(PyExc_DeprecationWarning,
		             "don't use 0 for anonymous memory",
			     1);
1180 1181
	 */
	if (fileno != -1 && fileno != 0) {
Mark Hammond's avatar
Mark Hammond committed
1182 1183
		fh = (HANDLE)_get_osfhandle(fileno);
		if (fh==(HANDLE)-1) {
1184 1185
			PyErr_SetFromErrno(mmap_module_error);
			return NULL;
1186
		}
1187
		/* Win9x appears to need us seeked to zero */
1188
		lseek(fileno, 0, SEEK_SET);
1189 1190
	}

1191
	m_obj = (mmap_object *)type->tp_alloc(type, 0);
1192
	if (m_obj == NULL)
1193 1194 1195 1196
		return NULL;
	/* Set every field to an invalid marker, so we can safely
	   destruct the object in the face of failure */
	m_obj->data = NULL;
Mark Hammond's avatar
Mark Hammond committed
1197
	m_obj->file_handle = INVALID_HANDLE_VALUE;
1198 1199
	m_obj->map_handle = INVALID_HANDLE_VALUE;
	m_obj->tagname = NULL;
1200
	m_obj->offset = offset;
1201

1202
	if (fh) {
1203 1204 1205
		/* It is necessary to duplicate the handle, so the
		   Python code can close it on us */
		if (!DuplicateHandle(
1206 1207 1208 1209 1210 1211 1212
			GetCurrentProcess(), /* source process handle */
			fh, /* handle to be duplicated */
			GetCurrentProcess(), /* target proc handle */
			(LPHANDLE)&m_obj->file_handle, /* result */
			0, /* access - ignored due to options value */
			FALSE, /* inherited by child processes? */
			DUPLICATE_SAME_ACCESS)) { /* options */
1213 1214 1215 1216 1217
			dwErr = GetLastError();
			Py_DECREF(m_obj);
			PyErr_SetFromWindowsErr(dwErr);
			return NULL;
		}
1218
		if (!map_size) {
1219 1220 1221 1222 1223 1224 1225 1226
			DWORD low,high;
			low = GetFileSize(fh, &high);
			/* low might just happen to have the value INVALID_FILE_SIZE;
    			   so we need to check the last error also. */
			if (low == INVALID_FILE_SIZE &&
			    (dwErr = GetLastError()) != NO_ERROR) {
				Py_DECREF(m_obj);
				return PyErr_SetFromWindowsErr(dwErr);
1227 1228
			}

1229 1230 1231 1232 1233 1234 1235 1236 1237
#if SIZEOF_SIZE_T > 4
			m_obj->size = (((size_t)high)<<32) + low;
#else
			if (high)
				/* File is too large to map completely */
				m_obj->size = (size_t)-1;
			else
				m_obj->size = low;
#endif
1238 1239
		} else {
			m_obj->size = map_size;
1240
		}
1241 1242 1243 1244 1245 1246 1247 1248
	}
	else {
		m_obj->size = map_size;
	}

	/* set the initial position */
	m_obj->pos = (size_t) 0;

1249
	m_obj->exports = 0;
1250
	/* set the tag name */
1251
	if (tagname != NULL && *tagname != '\0') {
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
		m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
		if (m_obj->tagname == NULL) {
			PyErr_NoMemory();
			Py_DECREF(m_obj);
			return NULL;
		}
		strcpy(m_obj->tagname, tagname);
	}
	else
		m_obj->tagname = NULL;

1263
	m_obj->access = (access_mode)access;
1264
	/* DWORD is a 4-byte int.  If we're on a box where size_t consumes
Thomas Wouters's avatar
Thomas Wouters committed
1265
	 * more than 4 bytes, we need to break it apart.  Else (size_t
1266 1267 1268 1269
	 * consumes 4 bytes), C doesn't define what happens if we shift
	 * right by 32, so we need different code.
	 */
#if SIZEOF_SIZE_T > 4
1270 1271 1272 1273
	size_hi = (DWORD)((offset + m_obj->size) >> 32);
	size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
	off_hi = (DWORD)(offset >> 32);
	off_lo = (DWORD)(offset & 0xFFFFFFFF);
1274 1275
#else
	size_hi = 0;
1276 1277 1278
	size_lo = (DWORD)(offset + m_obj->size);
	off_hi = 0;
	off_lo = (DWORD)offset;
1279
#endif
1280 1281
	/* For files, it would be sufficient to pass 0 as size.
	   For anonymous maps, we have to pass the size explicitly. */
1282 1283 1284 1285 1286 1287
	m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
					      NULL,
					      flProtect,
					      size_hi,
					      size_lo,
					      m_obj->tagname);
1288
	if (m_obj->map_handle != NULL) {
1289 1290
		m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
						     dwDesiredAccess,
1291 1292
						     off_hi,
						     off_lo,
1293
						     0);
1294 1295 1296
		if (m_obj->data != NULL)
			return (PyObject *)m_obj;
		else
1297
			dwErr = GetLastError();
1298
	} else
1299
		dwErr = GetLastError();
1300
	Py_DECREF(m_obj);
1301
	PyErr_SetFromWindowsErr(dwErr);
1302
	return NULL;
1303
}
1304
#endif /* MS_WINDOWS */
1305

1306 1307 1308
static void
setint(PyObject *d, const char *name, long value)
{
1309
	PyObject *o = PyLong_FromLong(value);
1310 1311 1312 1313 1314
	if (o && PyDict_SetItemString(d, name, o) == 0) {
		Py_DECREF(o);
	}
}

1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327

static struct PyModuleDef mmapmodule = {
	PyModuleDef_HEAD_INIT,
	"mmap",
	NULL,
	-1,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL
};

1328
PyMODINIT_FUNC
1329
PyInit_mmap(void)
1330
{
1331
	PyObject *dict, *module;
1332

1333
	if (PyType_Ready(&mmap_object_type) < 0)
1334
		return NULL;
1335

1336
	module = PyModule_Create(&mmapmodule);
1337
	if (module == NULL)
1338
		return NULL;
1339
	dict = PyModule_GetDict(module);
1340
	if (!dict)
1341
		return NULL;
Christian Heimes's avatar
Christian Heimes committed
1342 1343 1344
	mmap_module_error = PyErr_NewException("mmap.error",
		PyExc_EnvironmentError , NULL);
	if (mmap_module_error == NULL)
1345
		return NULL;
1346
	PyDict_SetItemString(dict, "error", mmap_module_error);
1347
	PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
1348
#ifdef PROT_EXEC
1349
	setint(dict, "PROT_EXEC", PROT_EXEC);
1350 1351
#endif
#ifdef PROT_READ
1352
	setint(dict, "PROT_READ", PROT_READ);
1353 1354
#endif
#ifdef PROT_WRITE
1355
	setint(dict, "PROT_WRITE", PROT_WRITE);
1356 1357 1358
#endif

#ifdef MAP_SHARED
1359
	setint(dict, "MAP_SHARED", MAP_SHARED);
1360 1361
#endif
#ifdef MAP_PRIVATE
1362
	setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
1363 1364
#endif
#ifdef MAP_DENYWRITE
1365
	setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
1366 1367
#endif
#ifdef MAP_EXECUTABLE
1368
	setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
1369
#endif
1370
#ifdef MAP_ANONYMOUS
1371 1372
	setint(dict, "MAP_ANON", MAP_ANONYMOUS);
	setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
1373 1374
#endif

1375
	setint(dict, "PAGESIZE", (long)my_getpagesize());
1376

1377 1378
	setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity()); 

1379 1380 1381
	setint(dict, "ACCESS_READ", ACCESS_READ);
	setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
	setint(dict, "ACCESS_COPY", ACCESS_COPY);
1382
	return module;
1383
}