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