PageRenderTime 1114ms CodeModel.GetById 111ms app.highlight 810ms RepoModel.GetById 177ms app.codeStats 1ms

/Modules/mmapmodule.c

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