mmapmodule.c 32.5 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

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

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

        access_mode access;
106 107
} mmap_object;

108

109
static void
Fredrik Lundh's avatar
Fredrik Lundh committed
110
mmap_object_dealloc(mmap_object *m_obj)
111
{
112
#ifdef MS_WINDOWS
113 114 115 116
	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
117 118
	if (m_obj->file_handle != INVALID_HANDLE_VALUE)
		CloseHandle (m_obj->file_handle);
119 120
	if (m_obj->tagname)
		PyMem_Free(m_obj->tagname);
121
#endif /* MS_WINDOWS */
122 123

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

132
	PyObject_Del(m_obj);
133 134 135
}

static PyObject *
136
mmap_close_method(mmap_object *self, PyObject *unused)
137
{
138
#ifdef MS_WINDOWS
Mark Hammond's avatar
Mark Hammond committed
139
	/* For each resource we maintain, we need to check
140
	   the value is valid, and if so, free the resource
Mark Hammond's avatar
Mark Hammond committed
141 142 143 144 145 146
	   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) {
147
		UnmapViewOfFile(self->data);
Mark Hammond's avatar
Mark Hammond committed
148 149 150
		self->data = NULL;
	}
	if (self->map_handle != INVALID_HANDLE_VALUE) {
151
		CloseHandle(self->map_handle);
Mark Hammond's avatar
Mark Hammond committed
152 153 154
		self->map_handle = INVALID_HANDLE_VALUE;
	}
	if (self->file_handle != INVALID_HANDLE_VALUE) {
155
		CloseHandle(self->file_handle);
Mark Hammond's avatar
Mark Hammond committed
156 157
		self->file_handle = INVALID_HANDLE_VALUE;
	}
158
#endif /* MS_WINDOWS */
159 160

#ifdef UNIX
161 162
	(void) close(self->fd);
	self->fd = -1;
163 164 165 166
	if (self->data != NULL) {
		munmap(self->data, self->size);
		self->data = NULL;
	}
167 168
#endif

169
	Py_INCREF(Py_None);
170
	return Py_None;
171 172
}

173
#ifdef MS_WINDOWS
174 175
#define CHECK_VALID(err)						\
do {									\
176
    if (self->map_handle == INVALID_HANDLE_VALUE) {						\
177
	PyErr_SetString(PyExc_ValueError, "mmap closed or invalid");	\
178 179
	return err;							\
    }									\
180
} while (0)
181
#endif /* MS_WINDOWS */
182 183

#ifdef UNIX
184 185 186
#define CHECK_VALID(err)						\
do {									\
    if (self->data == NULL) {						\
187
	PyErr_SetString(PyExc_ValueError, "mmap closed or invalid");	\
188 189
	return err;							\
	}								\
190 191 192 193
} while (0)
#endif /* UNIX */

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

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
209
mmap_read_line_method(mmap_object *self,
210
		      PyObject *unused)
211
{
Fredrik Lundh's avatar
Fredrik Lundh committed
212 213 214 215
	char *start = self->data+self->pos;
	char *eof = self->data+self->size;
	char *eol;
	PyObject *result;
216 217 218

	CHECK_VALID(NULL);

219 220 221 222 223 224
	eol = memchr(start, '\n', self->size - self->pos);
	if (!eol)
		eol = eof;
	else
		++eol;		/* we're interested in the position after the
				   newline. */
225
	result = PyString_FromStringAndSize(start, (eol - start));
226
	self->pos += (eol - start);
227
	return result;
228 229 230
}

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
231 232
mmap_read_method(mmap_object *self,
		 PyObject *args)
233
{
234
	Py_ssize_t num_bytes;
235 236 237
	PyObject *result;

	CHECK_VALID(NULL);
238
	if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
239 240 241 242 243 244 245
		return(NULL);

	/* silently 'adjust' out-of-range requests */
	if ((self->pos + num_bytes) > self->size) {
		num_bytes -= (self->pos+num_bytes) - self->size;
	}
	result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
246
	self->pos += num_bytes;
247
	return result;
248 249 250
}

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
251 252
mmap_find_method(mmap_object *self,
		 PyObject *args)
253
{
254
	Py_ssize_t start = self->pos;
Fredrik Lundh's avatar
Fredrik Lundh committed
255
	char *needle;
256
	Py_ssize_t len;
257

258
	CHECK_VALID(NULL);
259
	if (!PyArg_ParseTuple(args, "s#|n:find", &needle, &len, &start)) {
260 261
		return NULL;
	} else {
262 263 264 265
		char *p;
		char *e = self->data + self->size;

                if (start < 0)
266
			start += self->size;
267
                if (start < 0)
268
			start = 0;
269
                else if ((size_t)start > self->size)
270
			start = self->size;
271

272
		for (p = self->data + start; p + len <= e; ++p) {
273
			Py_ssize_t i;
274 275 276
			for (i = 0; i < len && needle[i] == p[i]; ++i)
				/* nothing */;
			if (i == len) {
277
				return PyInt_FromSsize_t(p - self->data);
278
			}
279
		}
280
		return PyInt_FromLong(-1);
281
	}
282 283
}

284
static int
285 286 287
is_writeable(mmap_object *self)
{
	if (self->access != ACCESS_READ)
288
		return 1;
289 290 291 292
	PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
	return 0;
}

293
static int
294 295 296
is_resizeable(mmap_object *self)
{
	if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
297 298
		return 1;
	PyErr_Format(PyExc_TypeError,
299 300 301 302 303
		     "mmap can't resize a readonly or copy-on-write memory map.");
	return 0;
}


304
static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
305 306
mmap_write_method(mmap_object *self,
		  PyObject *args)
307
{
308
	Py_ssize_t length;
Fredrik Lundh's avatar
Fredrik Lundh committed
309
	char *data;
310

311
	CHECK_VALID(NULL);
312
	if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
313
		return(NULL);
314

315 316 317
	if (!is_writeable(self))
		return NULL;

318
	if ((self->pos + length) > self->size) {
319
		PyErr_SetString(PyExc_ValueError, "data out of range");
320 321
		return NULL;
	}
322
	memcpy(self->data+self->pos, data, length);
323
	self->pos = self->pos+length;
324
	Py_INCREF(Py_None);
325
	return Py_None;
326 327 328
}

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
329 330
mmap_write_byte_method(mmap_object *self,
		       PyObject *args)
331
{
332
	char value;
333

334
	CHECK_VALID(NULL);
335
	if (!PyArg_ParseTuple(args, "c:write_byte", &value))
336
		return(NULL);
337

338 339
	if (!is_writeable(self))
		return NULL;
340 341
	*(self->data+self->pos) = value;
	self->pos += 1;
342
	Py_INCREF(Py_None);
343
	return Py_None;
344
}
345

346
static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
347
mmap_size_method(mmap_object *self,
348
		 PyObject *unused)
349
{
350
	CHECK_VALID(NULL);
351

352
#ifdef MS_WINDOWS
Mark Hammond's avatar
Mark Hammond committed
353
	if (self->file_handle != INVALID_HANDLE_VALUE) {
354 355 356 357 358 359 360 361 362 363 364 365 366 367
		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)
			return PyInt_FromLong((long)low);
		size = (((PY_LONG_LONG)high)<<32) + low;
		return PyLong_FromLongLong(size);
368
	} else {
369
		return PyInt_FromSsize_t(self->size);
370
	}
371
#endif /* MS_WINDOWS */
372 373

#ifdef UNIX
374 375 376 377 378 379
	{
		struct stat buf;
		if (-1 == fstat(self->fd, &buf)) {
			PyErr_SetFromErrno(mmap_module_error);
			return NULL;
		}
380
		return PyInt_FromSsize_t(buf.st_size);
381
	}
382 383 384 385 386 387 388 389 390 391 392 393 394
#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
395 396
mmap_resize_method(mmap_object *self,
		   PyObject *args)
397
{
398
	Py_ssize_t new_size;
399
	CHECK_VALID(NULL);
400
	if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
401
	    !is_resizeable(self)) {
402
		return NULL;
403
#ifdef MS_WINDOWS
404
	} else {
405
		DWORD dwErrCode = 0;
406
		DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
407
		/* First, unmap the file view */
408
		UnmapViewOfFile(self->data);
409
		/* Close the mapping object */
410
		CloseHandle(self->map_handle);
411
		/* Move to the desired EOF position */
412
#if SIZEOF_SIZE_T > 4
413 414 415 416
		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);
417 418
#else
		newSizeHigh = 0;
Martin v. Löwis's avatar
Martin v. Löwis committed
419
		newSizeLow = (DWORD)new_size;
420 421
		off_hi = 0;
		off_lo = (DWORD)self->offset;
422
#endif
423
		SetFilePointer(self->file_handle,
424
			       newSizeLow, &newSizeHigh, FILE_BEGIN);
425
		/* Change the size of the file */
426
		SetEndOfFile(self->file_handle);
427
		/* Create another mapping object and remap the file view */
428
		self->map_handle = CreateFileMapping(
Mark Hammond's avatar
Mark Hammond committed
429
			self->file_handle,
430 431
			NULL,
			PAGE_READWRITE,
432 433
			0,
			0,
434 435
			self->tagname);
		if (self->map_handle != NULL) {
436 437
			self->data = (char *) MapViewOfFile(self->map_handle,
							    FILE_MAP_WRITE,
438 439 440
							    off_hi,
							    off_lo,
							    new_size);
441 442
			if (self->data != NULL) {
				self->size = new_size;
443
				Py_INCREF(Py_None);
444 445 446 447 448 449
				return Py_None;
			} else {
				dwErrCode = GetLastError();
			}
		} else {
			dwErrCode = GetLastError();
450
		}
451
		PyErr_SetFromWindowsErr(dwErrCode);
452
		return NULL;
453
#endif /* MS_WINDOWS */
454 455

#ifdef UNIX
456
#ifndef HAVE_MREMAP
457 458 459 460
	} else {
		PyErr_SetString(PyExc_SystemError,
				"mmap: resizing not available--no mremap()");
		return NULL;
461
#else
462
	} else {
Armin Rigo's avatar
Armin Rigo committed
463 464
		void *newmap;

465 466 467 468
		if (ftruncate(self->fd, new_size) == -1) {
			PyErr_SetFromErrno(mmap_module_error);
			return NULL;
		}
469

470
#ifdef MREMAP_MAYMOVE
471
		newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
472
#else
473
		newmap = mremap(self->data, self->size, new_size, 0);
474
#endif
475
		if (newmap == (void *)-1)
476 477 478 479 480 481 482 483
		{
			PyErr_SetFromErrno(mmap_module_error);
			return NULL;
		}
		self->data = newmap;
		self->size = new_size;
		Py_INCREF(Py_None);
		return Py_None;
484
#endif /* HAVE_MREMAP */
485
#endif /* UNIX */
486
	}
487 488 489
}

static PyObject *
490
mmap_tell_method(mmap_object *self, PyObject *unused)
491
{
492
	CHECK_VALID(NULL);
493
	return PyInt_FromSize_t(self->pos);
494 495 496
}

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
497
mmap_flush_method(mmap_object *self, PyObject *args)
498
{
499 500
	Py_ssize_t offset = 0;
	Py_ssize_t size = self->size;
501
	CHECK_VALID(NULL);
502
	if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
503
		return NULL;
504
	if ((size_t)(offset + size) > self->size) {
505
		PyErr_SetString(PyExc_ValueError, "flush values out of range");
506 507
		return NULL;
	} else {
508
#ifdef MS_WINDOWS
509
		return PyInt_FromLong((long)
510
                                      FlushViewOfFile(self->data+offset, size));
511
#endif /* MS_WINDOWS */
512
#ifdef UNIX
513 514 515
		/* XXX semantics of return value? */
		/* XXX flags for msync? */
		if (-1 == msync(self->data + offset, size,
516
				MS_SYNC))
517 518 519
		{
			PyErr_SetFromErrno(mmap_module_error);
			return NULL;
520
		}
521
		return PyInt_FromLong(0);
522
#endif /* UNIX */
523
	}
524 525 526
}

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
527
mmap_seek_method(mmap_object *self, PyObject *args)
528
{
529
	Py_ssize_t dist;
530 531
	int how=0;
	CHECK_VALID(NULL);
532
	if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
533 534
		return NULL;
	else {
535
		size_t where;
536
		switch (how) {
537 538 539
		case 0: /* relative to start */
			if (dist < 0)
				goto onoutofrange;
540 541
			where = dist;
			break;
542
		case 1: /* relative to current position */
543
			if ((Py_ssize_t)self->pos + dist < 0)
544
				goto onoutofrange;
545 546
			where = self->pos + dist;
			break;
547
		case 2: /* relative to end */
548
			if ((Py_ssize_t)self->size + dist < 0)
549 550
				goto onoutofrange;
			where = self->size + dist;
551 552
			break;
		default:
553
			PyErr_SetString(PyExc_ValueError, "unknown seek type");
554 555
			return NULL;
		}
556 557 558
		if (where > self->size)
			goto onoutofrange;
		self->pos = where;
559
		Py_INCREF(Py_None);
560
		return Py_None;
561
	}
562

563
  onoutofrange:
564
	PyErr_SetString(PyExc_ValueError, "seek out of range");
565
	return NULL;
566 567 568
}

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
569
mmap_move_method(mmap_object *self, PyObject *args)
570
{
571 572
	unsigned long dest, src, count;
	CHECK_VALID(NULL);
573
	if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) ||
574
	    !is_writeable(self)) {
575 576 577 578 579 580 581
		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)) {
582 583
			PyErr_SetString(PyExc_ValueError,
					"source or destination out of range");
584
			return NULL;
585
		} else {
586 587
			memmove(self->data+dest, self->data+src, count);
			Py_INCREF(Py_None);
588
			return Py_None;
589
		}
590
	}
591 592 593
}

static struct PyMethodDef mmap_object_methods[] = {
594
	{"close",	(PyCFunction) mmap_close_method,	METH_NOARGS},
595 596 597 598
	{"find",	(PyCFunction) mmap_find_method,		METH_VARARGS},
	{"flush",	(PyCFunction) mmap_flush_method,	METH_VARARGS},
	{"move",	(PyCFunction) mmap_move_method,		METH_VARARGS},
	{"read",	(PyCFunction) mmap_read_method,		METH_VARARGS},
599 600
	{"read_byte",	(PyCFunction) mmap_read_byte_method,  	METH_NOARGS},
	{"readline",	(PyCFunction) mmap_read_line_method,	METH_NOARGS},
601 602
	{"resize",	(PyCFunction) mmap_resize_method,	METH_VARARGS},
	{"seek",	(PyCFunction) mmap_seek_method,		METH_VARARGS},
603 604
	{"size",	(PyCFunction) mmap_size_method,		METH_NOARGS},
	{"tell",	(PyCFunction) mmap_tell_method,		METH_NOARGS},
605 606
	{"write",	(PyCFunction) mmap_write_method,	METH_VARARGS},
	{"write_byte",	(PyCFunction) mmap_write_byte_method,	METH_VARARGS},
607
	{NULL,	   NULL}       /* sentinel */
608 609 610 611
};

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

Martin v. Löwis's avatar
Martin v. Löwis committed
612 613
static Py_ssize_t
mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
614
{
615
	CHECK_VALID(-1);
616
	if (index != 0) {
617 618 619 620 621 622
		PyErr_SetString(PyExc_SystemError,
				"Accessing non-existent mmap segment");
		return -1;
	}
	*ptr = self->data;
	return self->size;
623 624
}

Martin v. Löwis's avatar
Martin v. Löwis committed
625 626
static Py_ssize_t
mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
627
{
628
	CHECK_VALID(-1);
629
	if (index != 0) {
630 631 632 633
		PyErr_SetString(PyExc_SystemError,
				"Accessing non-existent mmap segment");
		return -1;
	}
634 635
	if (!is_writeable(self))
		return -1;
636 637
	*ptr = self->data;
	return self->size;
638 639
}

Martin v. Löwis's avatar
Martin v. Löwis committed
640 641
static Py_ssize_t
mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
642
{
643
	CHECK_VALID(-1);
644
	if (lenp)
645 646
		*lenp = self->size;
	return 1;
647 648
}

Martin v. Löwis's avatar
Martin v. Löwis committed
649 650
static Py_ssize_t
mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
651
{
652
	if (index != 0) {
653 654 655 656 657 658
		PyErr_SetString(PyExc_SystemError,
				"accessing non-existent buffer segment");
		return -1;
	}
	*ptr = (const char *)self->data;
	return self->size;
659 660 661
}

static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
662
mmap_object_getattr(mmap_object *self, char *name)
663
{
664
	return Py_FindMethod(mmap_object_methods, (PyObject *)self, name);
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 682
		PyErr_SetString(PyExc_IndexError, "mmap index out of range");
		return NULL;
	}
	return PyString_FromStringAndSize(self->data + i, 1);
683 684 685
}

static PyObject *
Martin v. Löwis's avatar
Martin v. Löwis committed
686
mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
687
{
688 689 690
	CHECK_VALID(NULL);
	if (ilow < 0)
		ilow = 0;
691
	else if ((size_t)ilow > self->size)
692 693 694 695 696
		ilow = self->size;
	if (ihigh < 0)
		ihigh = 0;
	if (ihigh < ilow)
		ihigh = ilow;
697
	else if ((size_t)ihigh > self->size)
698
		ihigh = self->size;
699

700
	return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
701 702
}

703 704 705 706 707 708 709 710 711 712
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;
713
		if (i < 0 || (size_t)i > self->size) {
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
			PyErr_SetString(PyExc_IndexError,
				"mmap index out of range");
			return NULL;
		}
		return PyString_FromStringAndSize(self->data + i, 1);
	}
	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;
		}
		
		if (slicelen <= 0)
			return PyString_FromStringAndSize("", 0);
		else if (step == 1)
			return PyString_FromStringAndSize(self->data + start,
							  slicelen);
		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];
			}
			result = PyString_FromStringAndSize(result_buf,
							    slicelen);
			PyMem_Free(result_buf);
			return result;
		}
	}
	else {
		PyErr_SetString(PyExc_TypeError,
				"mmap indices must be integers");
		return NULL;
	}
}

757
static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
758
mmap_concat(mmap_object *self, PyObject *bb)
759
{
760 761 762 763
	CHECK_VALID(NULL);
	PyErr_SetString(PyExc_SystemError,
			"mmaps don't support concatenation");
	return NULL;
764 765 766
}

static PyObject *
Martin v. Löwis's avatar
Martin v. Löwis committed
767
mmap_repeat(mmap_object *self, Py_ssize_t n)
768
{
769 770 771 772
	CHECK_VALID(NULL);
	PyErr_SetString(PyExc_SystemError,
			"mmaps don't support repeat operation");
	return NULL;
773 774 775
}

static int
Martin v. Löwis's avatar
Martin v. Löwis committed
776
mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
777
{
778
	const char *buf;
779 780 781 782

	CHECK_VALID(-1);
	if (ilow < 0)
		ilow = 0;
783
	else if ((size_t)ilow > self->size)
784 785 786 787 788
		ilow = self->size;
	if (ihigh < 0)
		ihigh = 0;
	if (ihigh < ilow)
		ihigh = ilow;
789
	else if ((size_t)ihigh > self->size)
790
		ihigh = self->size;
791

792 793
	if (v == NULL) {
		PyErr_SetString(PyExc_TypeError,
794
				"mmap object doesn't support slice deletion");
795 796
		return -1;
	}
797
	if (! (PyString_Check(v)) ) {
798
		PyErr_SetString(PyExc_IndexError,
799 800 801
				"mmap slice assignment must be a string");
		return -1;
	}
802
	if (PyString_Size(v) != (ihigh - ilow)) {
803
		PyErr_SetString(PyExc_IndexError,
804 805 806
				"mmap slice assignment is wrong size");
		return -1;
	}
807 808
	if (!is_writeable(self))
		return -1;
809 810 811
	buf = PyString_AsString(v);
	memcpy(self->data + ilow, buf, ihigh-ilow);
	return 0;
812 813 814
}

static int
Martin v. Löwis's avatar
Martin v. Löwis committed
815
mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
816
{
817
	const char *buf;
818

819
	CHECK_VALID(-1);
820
	if (i < 0 || (size_t)i >= self->size) {
821 822 823
		PyErr_SetString(PyExc_IndexError, "mmap index out of range");
		return -1;
	}
824 825
	if (v == NULL) {
		PyErr_SetString(PyExc_TypeError,
826
				"mmap object doesn't support item deletion");
827 828
		return -1;
	}
829
	if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
830
		PyErr_SetString(PyExc_IndexError,
831
				"mmap assignment must be single-character string");
832 833
		return -1;
	}
834 835
	if (!is_writeable(self))
		return -1;
836 837 838
	buf = PyString_AsString(v);
	self->data[i] = buf[0];
	return 0;
839 840
}

841 842 843 844 845 846 847 848 849 850 851 852 853
static int
mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
{
	CHECK_VALID(-1);

	if (PyIndex_Check(item)) {
		Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
		const char *buf;

		if (i == -1 && PyErr_Occurred())
			return -1;
		if (i < 0)
			i += self->size;
854
		if (i < 0 || (size_t)i > self->size) {
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930
			PyErr_SetString(PyExc_IndexError,
				"mmap index out of range");
			return -1;
		}
		if (value == NULL) {
			PyErr_SetString(PyExc_TypeError,
				"mmap object doesn't support item deletion");
			return -1;
		}
		if (!PyString_Check(value) || PyString_Size(value) != 1) {
			PyErr_SetString(PyExc_IndexError,
		          "mmap assignment must be single-character string");
			return -1;
		}
		if (!is_writeable(self))
			return -1;
		buf = PyString_AsString(value);
		self->data[i] = buf[0];
		return 0;
	}
	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 -1;
		}
		if (value == NULL) {
			PyErr_SetString(PyExc_TypeError,
				"mmap object doesn't support slice deletion");
			return -1;
		}
		if (!PyString_Check(value)) {
			PyErr_SetString(PyExc_IndexError,
				"mmap slice assignment must be a string");
			return -1;
		}
		if (PyString_Size(value) != slicelen) {
			PyErr_SetString(PyExc_IndexError,
				"mmap slice assignment is wrong size");
			return -1;
		}
		if (!is_writeable(self))
			return -1;

		if (slicelen == 0)
			return 0;
		else if (step == 1) {
			const char *buf = PyString_AsString(value);

			if (buf == NULL)
				return -1;
			memcpy(self->data + start, buf, slicelen);
			return 0;
		}
		else {
			Py_ssize_t cur, i;
			const char *buf = PyString_AsString(value);
			
			if (buf == NULL)
				return -1;
			for (cur = start, i = 0; i < slicelen;
			     cur += step, i++) {
				self->data[cur] = buf[i];
			}
			return 0;
		}
	}
	else {
		PyErr_SetString(PyExc_TypeError,
				"mmap indices must be integer");
		return -1;
	}
}

931
static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis's avatar
Martin v. Löwis committed
932
	(lenfunc)mmap_length,		       /*sq_length*/
933
	(binaryfunc)mmap_concat,	       /*sq_concat*/
Martin v. Löwis's avatar
Martin v. Löwis committed
934 935 936 937 938
	(ssizeargfunc)mmap_repeat,	       /*sq_repeat*/
	(ssizeargfunc)mmap_item,		       /*sq_item*/
	(ssizessizeargfunc)mmap_slice,	       /*sq_slice*/
	(ssizeobjargproc)mmap_ass_item,	       /*sq_ass_item*/
	(ssizessizeobjargproc)mmap_ass_slice,      /*sq_ass_slice*/
939 940
};

941 942 943 944 945 946
static PyMappingMethods mmap_as_mapping = {
	(lenfunc)mmap_length,
	(binaryfunc)mmap_subscript,
	(objobjargproc)mmap_ass_subscript,
};

947
static PyBufferProcs mmap_as_buffer = {
Martin v. Löwis's avatar
Martin v. Löwis committed
948 949 950 951
	(readbufferproc)mmap_buffer_getreadbuf,
	(writebufferproc)mmap_buffer_getwritebuf,
	(segcountproc)mmap_buffer_getsegcount,
	(charbufferproc)mmap_buffer_getcharbuffer,
952 953 954
};

static PyTypeObject mmap_object_type = {
955
	PyVarObject_HEAD_INIT(0, 0) /* patched in module init */
956
	"mmap.mmap",				/* tp_name */
957 958 959 960 961 962 963 964 965 966 967
	sizeof(mmap_object),			/* tp_size */
	0,					/* tp_itemsize */
	/* methods */
	(destructor) mmap_object_dealloc,	/* tp_dealloc */
	0,					/* tp_print */
	(getattrfunc) mmap_object_getattr,	/* tp_getattr */
	0,					/* tp_setattr */
	0,					/* tp_compare */
	0,					/* tp_repr */
	0,					/* tp_as_number */
	&mmap_as_sequence,			/*tp_as_sequence*/
968
	&mmap_as_mapping,			/*tp_as_mapping*/
969 970 971 972 973 974 975 976
	0,					/*tp_hash*/
	0,					/*tp_call*/
	0,					/*tp_str*/
	0,					/*tp_getattro*/
	0,					/*tp_setattro*/
	&mmap_as_buffer,			/*tp_as_buffer*/
	Py_TPFLAGS_HAVE_GETCHARBUFFER,		/*tp_flags*/
	0,					/*tp_doc*/
977 978
};

979 980 981

/* extract the map size from the given PyObject

982
   Returns -1 on error, with an appropriate Python exception raised. On
983
   success, the map size is returned. */
984
static Py_ssize_t
985
_GetMapSize(PyObject *o, const char* param)
986
{
987 988
	if (o == NULL)
		return 0;
989 990
	if (PyIndex_Check(o)) {
		Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
991
		if (i==-1 && PyErr_Occurred()) 
992
			return -1;
993
		if (i < 0) {	 
994 995 996
			PyErr_Format(PyExc_OverflowError,
					"memory mapped %s must be positive",
                                        param);
997 998
			return -1;
		}
999
		return i;
1000 1001
	}

1002
	PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1003 1004 1005
	return -1;
}

1006
#ifdef UNIX
1007
static PyObject *
Fredrik Lundh's avatar
Fredrik Lundh committed
1008
new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
1009
{
1010 1011 1012
#ifdef HAVE_FSTAT
	struct stat st;
#endif
Fredrik Lundh's avatar
Fredrik Lundh committed
1013
	mmap_object *m_obj;
1014 1015
	PyObject *map_size_obj = NULL, *offset_obj = NULL;
	Py_ssize_t map_size, offset;
1016
	int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1017
	int devzero = -1;
1018
	int access = (int)ACCESS_DEFAULT;
Martin v. Löwis's avatar
Martin v. Löwis committed
1019
	static char *keywords[] = {"fileno", "length",
1020
                                         "flags", "prot",
1021
                                         "access", "offset", NULL};
1022

1023
	if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
1024
					 &fd, &map_size_obj, &flags, &prot,
1025
                                         &access, &offset_obj))
1026
		return NULL;
1027
	map_size = _GetMapSize(map_size_obj, "size");
1028 1029
	if (map_size < 0)
		return NULL;
1030 1031 1032
        offset = _GetMapSize(offset_obj, "offset");
        if (offset < 0)
                return NULL;
1033

1034
	if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitz's avatar
Neal Norwitz committed
1035
	    ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1036
		return PyErr_Format(PyExc_ValueError,
1037
				    "mmap can't specify both access and flags, prot.");
Neal Norwitz's avatar
Neal Norwitz committed
1038
	switch ((access_mode)access) {
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050
	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;
1051
	case ACCESS_DEFAULT:
1052 1053 1054
		/* use the specified or default values of flags and prot */
		break;
	default:
1055
		return PyErr_Format(PyExc_ValueError,
1056 1057
				    "mmap invalid access parameter.");
	}
1058 1059

#ifdef HAVE_FSTAT
1060 1061 1062 1063
#  ifdef __VMS
	/* on OpenVMS we must ensure that all bytes are written to the file */
	fsync(fd);
#  endif
1064 1065
	if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
		if (map_size == 0) {
1066
			map_size = st.st_size;
1067
		} else if ((size_t)offset + (size_t)map_size > st.st_size) {
1068
			PyErr_SetString(PyExc_ValueError,
1069 1070 1071
					"mmap length is greater than file size");
			return NULL;
		}
1072 1073
	}
#endif
1074
	m_obj = PyObject_New(mmap_object, &mmap_object_type);
1075
	if (m_obj == NULL) {return NULL;}
1076
	m_obj->data = NULL;
1077 1078
	m_obj->size = (size_t) map_size;
	m_obj->pos = (size_t) 0;
1079
        m_obj->offset = offset;
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
	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;
		}
1105
	}
1106
	
1107
	m_obj->data = mmap(NULL, map_size,
1108
			   prot, flags,
1109
			   fd, offset);
1110 1111 1112 1113 1114

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

1115
	if (m_obj->data == (char *)-1) {
1116
	        m_obj->data = NULL;
1117 1118 1119 1120
		Py_DECREF(m_obj);
		PyErr_SetFromErrno(mmap_module_error);
		return NULL;
	}
1121
	m_obj->access = (access_mode)access;
1122
	return (PyObject *)m_obj;
1123 1124 1125
}
#endif /* UNIX */

1126
#ifdef MS_WINDOWS
1127
static PyObject *
1128
new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
1129
{
Fredrik Lundh's avatar
Fredrik Lundh committed
1130
	mmap_object *m_obj;
1131 1132 1133 1134 1135 1136
	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
1137
	char *tagname = "";
1138 1139
	DWORD dwErr = 0;
	int fileno;
Mark Hammond's avatar
Mark Hammond committed
1140
	HANDLE fh = 0;
1141
	int access = (access_mode)ACCESS_DEFAULT;
1142
	DWORD flProtect, dwDesiredAccess;
Martin v. Löwis's avatar
Martin v. Löwis committed
1143
	static char *keywords[] = { "fileno", "length",
1144
                                          "tagname",
1145
                                          "access", "offset", NULL };
1146

1147
	if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
1148
					 &fileno, &map_size_obj,
1149
					 &tagname, &access, &offset_obj)) {
1150
		return NULL;
1151 1152
	}

1153
	switch((access_mode)access) {
1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
	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:
1167
		return PyErr_Format(PyExc_ValueError,
1168 1169 1170
				    "mmap invalid access parameter.");
	}

1171
	map_size = _GetMapSize(map_size_obj, "size");
1172 1173
	if (map_size < 0)
		return NULL;
1174 1175 1176
        offset = _GetMapSize(offset_obj, "offset");
        if (offset < 0)
                return NULL;
1177

1178 1179 1180 1181 1182 1183 1184 1185 1186
	/* 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)
	   	PyErr_Warn(PyExc_DeprecationWarning,
			   "don't use 0 for anonymous memory");
	 */
	if (fileno != -1 && fileno != 0) {
Mark Hammond's avatar
Mark Hammond committed
1187 1188
		fh = (HANDLE)_get_osfhandle(fileno);
		if (fh==(HANDLE)-1) {
1189 1190
			PyErr_SetFromErrno(mmap_module_error);
			return NULL;
1191
		}
1192
		/* Win9x appears to need us seeked to zero */
1193
		lseek(fileno, 0, SEEK_SET);
1194 1195
	}

1196 1197
	m_obj = PyObject_New(mmap_object, &mmap_object_type);
	if (m_obj == NULL)
1198 1199 1200 1201
		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
1202
	m_obj->file_handle = INVALID_HANDLE_VALUE;
1203 1204
	m_obj->map_handle = INVALID_HANDLE_VALUE;
	m_obj->tagname = NULL;
1205
	m_obj->offset = offset;
1206

1207
	if (fh) {
1208 1209 1210
		/* It is necessary to duplicate the handle, so the
		   Python code can close it on us */
		if (!DuplicateHandle(
1211 1212 1213 1214 1215 1216 1217
			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 */
1218 1219 1220 1221 1222
			dwErr = GetLastError();
			Py_DECREF(m_obj);
			PyErr_SetFromWindowsErr(dwErr);
			return NULL;
		}
1223
		if (!map_size) {
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
			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);
			}	
				    
#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
1243 1244
		} else {
			m_obj->size = map_size;
1245
		}
1246 1247 1248 1249 1250 1251 1252 1253
	}
	else {
		m_obj->size = map_size;
	}

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

1254
	/* set the tag name */
1255
	if (tagname != NULL && *tagname != '\0') {
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
		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;

1267
	m_obj->access = (access_mode)access;
1268
	/* DWORD is a 4-byte int.  If we're on a box where size_t consumes
Thomas Wouters's avatar
Thomas Wouters committed
1269
	 * more than 4 bytes, we need to break it apart.  Else (size_t
1270 1271 1272 1273
	 * 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
1274 1275 1276 1277
	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);
1278 1279
#else
	size_hi = 0;
1280 1281 1282
	size_lo = (DWORD)(offset + m_obj->size);
	off_hi = 0;
	off_lo = (DWORD)offset;
1283
#endif
1284 1285
	/* For files, it would be sufficient to pass 0 as size.
	   For anonymous maps, we have to pass the size explicitly. */
1286 1287 1288 1289 1290 1291
	m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
					      NULL,
					      flProtect,
					      size_hi,
					      size_lo,
					      m_obj->tagname);
1292
	if (m_obj->map_handle != NULL) {
1293 1294
		m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
						     dwDesiredAccess,
1295 1296
						     off_hi,
						     off_lo,
1297
						     0);
1298 1299 1300
		if (m_obj->data != NULL)
			return (PyObject *)m_obj;
		else
1301
			dwErr = GetLastError();
1302
	} else
1303
		dwErr = GetLastError();
1304
	Py_DECREF(m_obj);
1305
	PyErr_SetFromWindowsErr(dwErr);
1306
	return NULL;
1307
}
1308
#endif /* MS_WINDOWS */
1309 1310 1311

/* List of functions exported by this module */
static struct PyMethodDef mmap_functions[] = {
1312
	{"mmap",	(PyCFunction) new_mmap_object,
1313 1314
	 METH_VARARGS|METH_KEYWORDS},
	{NULL,		NULL}	     /* Sentinel */
1315 1316
};

1317 1318 1319 1320
static void
setint(PyObject *d, const char *name, long value)
{
	PyObject *o = PyInt_FromLong(value);
1321
	if (o && PyDict_SetItemString(d, name, o) == 0) {
1322
		Py_DECREF(o);
1323
	}
1324 1325
}

1326
PyMODINIT_FUNC
1327
	initmmap(void)
1328
{
1329
	PyObject *dict, *module;
1330 1331

	/* Patch the object type */
1332
	Py_Type(&mmap_object_type) = &PyType_Type;
1333

1334
	module = Py_InitModule("mmap", mmap_functions);
1335 1336
	if (module == NULL)
		return;
1337
	dict = PyModule_GetDict(module);
1338 1339
	if (!dict)
		return;
1340
	mmap_module_error = PyExc_EnvironmentError;
1341
	PyDict_SetItemString(dict, "error", mmap_module_error);
1342
#ifdef PROT_EXEC
1343
	setint(dict, "PROT_EXEC", PROT_EXEC);
1344 1345
#endif
#ifdef PROT_READ
1346
	setint(dict, "PROT_READ", PROT_READ);
1347 1348
#endif
#ifdef PROT_WRITE
1349
	setint(dict, "PROT_WRITE", PROT_WRITE);
1350 1351 1352
#endif

#ifdef MAP_SHARED
1353
	setint(dict, "MAP_SHARED", MAP_SHARED);
1354 1355
#endif
#ifdef MAP_PRIVATE
1356
	setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
1357 1358
#endif
#ifdef MAP_DENYWRITE
1359
	setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
1360 1361
#endif
#ifdef MAP_EXECUTABLE
1362
	setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
1363
#endif
1364
#ifdef MAP_ANONYMOUS
1365 1366
	setint(dict, "MAP_ANON", MAP_ANONYMOUS);
	setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
1367 1368
#endif

1369
	setint(dict, "PAGESIZE", (long)my_getpagesize());
1370

1371 1372
	setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity()); 

1373 1374 1375
	setint(dict, "ACCESS_READ", ACCESS_READ);
	setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
	setint(dict, "ACCESS_COPY", ACCESS_COPY);
1376
}