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