1 /* Author: Daniel Stutzbach */ 2 3 #define PY_SSIZE_T_CLEAN 4 #include "Python.h" 5 #ifdef HAVE_SYS_TYPES_H 6 #include <sys/types.h> 7 #endif 8 #ifdef HAVE_SYS_STAT_H 9 #include <sys/stat.h> 10 #endif 11 #ifdef HAVE_IO_H 12 #include <io.h> 13 #endif 14 #ifdef HAVE_FCNTL_H 15 #include <fcntl.h> 16 #endif 17 #include <stddef.h> /* For offsetof */ 18 #include "_iomodule.h" 19 20 /* 21 * Known likely problems: 22 * 23 * - Files larger then 2**32-1 24 * - Files with unicode filenames 25 * - Passing numbers greater than 2**32-1 when an integer is expected 26 * - Making it work on Windows and other oddball platforms 27 * 28 * To Do: 29 * 30 * - autoconfify header file inclusion 31 */ 32 33 #ifdef MS_WINDOWS 34 /* can simulate truncate with Win32 API functions; see file_truncate */ 35 #define HAVE_FTRUNCATE 36 #define WIN32_LEAN_AND_MEAN 37 #include <windows.h> 38 #endif 39 40 #if BUFSIZ < (8*1024) 41 #define SMALLCHUNK (8*1024) 42 #elif (BUFSIZ >= (2 << 25)) 43 #error "unreasonable BUFSIZ > 64MB defined" 44 #else 45 #define SMALLCHUNK BUFSIZ 46 #endif 47 48 typedef struct { 49 PyObject_HEAD 50 int fd; 51 unsigned int readable : 1; 52 unsigned int writable : 1; 53 unsigned int appending : 1; 54 signed int seekable : 2; /* -1 means unknown */ 55 unsigned int closefd : 1; 56 PyObject *weakreflist; 57 PyObject *dict; 58 } fileio; 59 60 PyTypeObject PyFileIO_Type; 61 62 #define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type)) 63 64 int 65 _PyFileIO_closed(PyObject *self) 66 { 67 return ((fileio *)self)->fd < 0; 68 } 69 70 static PyObject * 71 portable_lseek(int fd, PyObject *posobj, int whence); 72 73 static PyObject *portable_lseek(int fd, PyObject *posobj, int whence); 74 75 /* Returns 0 on success, -1 with exception set on failure. */ 76 static int 77 internal_close(fileio *self) 78 { 79 int err = 0; 80 int save_errno = 0; 81 if (self->fd >= 0) { 82 int fd = self->fd; 83 self->fd = -1; 84 /* fd is accessible and someone else may have closed it */ 85 if (_PyVerify_fd(fd)) { 86 Py_BEGIN_ALLOW_THREADS 87 err = close(fd); 88 if (err < 0) 89 save_errno = errno; 90 Py_END_ALLOW_THREADS 91 } else { 92 save_errno = errno; 93 err = -1; 94 } 95 } 96 if (err < 0) { 97 errno = save_errno; 98 PyErr_SetFromErrno(PyExc_IOError); 99 return -1; 100 } 101 return 0; 102 } 103 104 static PyObject * 105 fileio_close(fileio *self) 106 { 107 PyObject *res; 108 res = PyObject_CallMethod((PyObject*)&PyRawIOBase_Type, 109 "close", "O", self); 110 if (!self->closefd) { 111 self->fd = -1; 112 return res; 113 } 114 if (internal_close(self) < 0) 115 Py_CLEAR(res); 116 return res; 117 } 118 119 static PyObject * 120 fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) 121 { 122 fileio *self; 123 124 assert(type != NULL && type->tp_alloc != NULL); 125 126 self = (fileio *) type->tp_alloc(type, 0); 127 if (self != NULL) { 128 self->fd = -1; 129 self->readable = 0; 130 self->writable = 0; 131 self->appending = 0; 132 self->seekable = -1; 133 self->closefd = 1; 134 self->weakreflist = NULL; 135 } 136 137 return (PyObject *) self; 138 } 139 140 /* On Unix, open will succeed for directories. 141 In Python, there should be no file objects referring to 142 directories, so we need a check. */ 143 144 static int 145 dircheck(fileio* self, PyObject *nameobj) 146 { 147 #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR) 148 struct stat buf; 149 int res; 150 if (self->fd < 0) 151 return 0; 152 153 Py_BEGIN_ALLOW_THREADS 154 res = fstat(self->fd, &buf); 155 Py_END_ALLOW_THREADS 156 157 if (res == 0 && S_ISDIR(buf.st_mode)) { 158 errno = EISDIR; 159 PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj); 160 return -1; 161 } 162 #endif 163 return 0; 164 } 165 166 static int 167 check_fd(int fd) 168 { 169 #if defined(HAVE_FSTAT) 170 struct stat buf; 171 int res; 172 PyObject *exc; 173 char *msg; 174 175 if (!_PyVerify_fd(fd)) { 176 goto badfd; 177 } 178 179 Py_BEGIN_ALLOW_THREADS 180 res = fstat(fd, &buf); 181 Py_END_ALLOW_THREADS 182 183 if (res < 0 && errno == EBADF) { 184 goto badfd; 185 } 186 187 return 0; 188 189 badfd: 190 msg = strerror(EBADF); 191 exc = PyObject_CallFunction(PyExc_OSError, "(is)", 192 EBADF, msg); 193 PyErr_SetObject(PyExc_OSError, exc); 194 Py_XDECREF(exc); 195 return -1; 196 #else 197 return 0; 198 #endif 199 } 200 201 202 static int 203 fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) 204 { 205 fileio *self = (fileio *) oself; 206 static char *kwlist[] = {"file", "mode", "closefd", NULL}; 207 const char *name = NULL; 208 PyObject *nameobj, *stringobj = NULL; 209 char *mode = "r"; 210 char *s; 211 #ifdef MS_WINDOWS 212 Py_UNICODE *widename = NULL; 213 #endif 214 int ret = 0; 215 int rwa = 0, plus = 0; 216 int flags = 0; 217 int fd = -1; 218 int closefd = 1; 219 int fd_is_own = 0; 220 221 assert(PyFileIO_Check(oself)); 222 if (self->fd >= 0) { 223 if (self->closefd) { 224 /* Have to close the existing file first. */ 225 if (internal_close(self) < 0) 226 return -1; 227 } 228 else 229 self->fd = -1; 230 } 231 232 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|si:fileio", 233 kwlist, &nameobj, &mode, &closefd)) 234 return -1; 235 236 if (PyFloat_Check(nameobj)) { 237 PyErr_SetString(PyExc_TypeError, 238 "integer argument expected, got float"); 239 return -1; 240 } 241 242 fd = _PyLong_AsInt(nameobj); 243 if (fd < 0) { 244 if (!PyErr_Occurred()) { 245 PyErr_SetString(PyExc_ValueError, 246 "negative file descriptor"); 247 return -1; 248 } 249 PyErr_Clear(); 250 } 251 252 #ifdef MS_WINDOWS 253 if (PyUnicode_Check(nameobj)) { 254 widename = PyUnicode_AS_UNICODE(nameobj); 255 if (wcslen(widename) != (size_t)PyUnicode_GET_SIZE(nameobj)) { 256 PyErr_SetString(PyExc_TypeError, "embedded NUL character"); 257 return -1; 258 } 259 } 260 if (widename == NULL) 261 #endif 262 if (fd < 0) 263 { 264 if (PyBytes_Check(nameobj) || PyByteArray_Check(nameobj)) { 265 Py_ssize_t namelen; 266 if (PyObject_AsCharBuffer(nameobj, &name, &namelen) < 0) 267 return -1; 268 if (strlen(name) != (size_t)namelen) { 269 PyErr_SetString(PyExc_TypeError, "embedded NUL character"); 270 return -1; 271 } 272 } 273 else { 274 PyObject *u = PyUnicode_FromObject(nameobj); 275 276 if (u == NULL) 277 return -1; 278 279 stringobj = PyUnicode_AsEncodedString( 280 u, Py_FileSystemDefaultEncoding, NULL); 281 Py_DECREF(u); 282 if (stringobj == NULL) 283 return -1; 284 if (!PyBytes_Check(stringobj)) { 285 PyErr_SetString(PyExc_TypeError, 286 "encoder failed to return bytes"); 287 goto error; 288 } 289 name = PyBytes_AS_STRING(stringobj); 290 if (strlen(name) != (size_t)PyBytes_GET_SIZE(stringobj)) { 291 PyErr_SetString(PyExc_TypeError, "embedded NUL character"); 292 goto error; 293 } 294 } 295 } 296 297 s = mode; 298 while (*s) { 299 switch (*s++) { 300 case 'r': 301 if (rwa) { 302 bad_mode: 303 PyErr_SetString(PyExc_ValueError, 304 "Must have exactly one of read/write/append " 305 "mode and at most one plus"); 306 goto error; 307 } 308 rwa = 1; 309 self->readable = 1; 310 break; 311 case 'w': 312 if (rwa) 313 goto bad_mode; 314 rwa = 1; 315 self->writable = 1; 316 flags |= O_CREAT | O_TRUNC; 317 break; 318 case 'a': 319 if (rwa) 320 goto bad_mode; 321 rwa = 1; 322 self->writable = 1; 323 self->appending = 1; 324 flags |= O_APPEND | O_CREAT; 325 break; 326 case 'b': 327 break; 328 case '+': 329 if (plus) 330 goto bad_mode; 331 self->readable = self->writable = 1; 332 plus = 1; 333 break; 334 default: 335 PyErr_Format(PyExc_ValueError, 336 "invalid mode: %.200s", mode); 337 goto error; 338 } 339 } 340 341 if (!rwa) 342 goto bad_mode; 343 344 if (self->readable && self->writable) 345 flags |= O_RDWR; 346 else if (self->readable) 347 flags |= O_RDONLY; 348 else 349 flags |= O_WRONLY; 350 351 #ifdef O_BINARY 352 flags |= O_BINARY; 353 #endif 354 355 if (fd >= 0) { 356 if (check_fd(fd)) 357 goto error; 358 self->fd = fd; 359 self->closefd = closefd; 360 } 361 else { 362 self->closefd = 1; 363 if (!closefd) { 364 PyErr_SetString(PyExc_ValueError, 365 "Cannot use closefd=False with file name"); 366 goto error; 367 } 368 369 Py_BEGIN_ALLOW_THREADS 370 errno = 0; 371 #ifdef MS_WINDOWS 372 if (widename != NULL) 373 self->fd = _wopen(widename, flags, 0666); 374 else 375 #endif 376 self->fd = open(name, flags, 0666); 377 Py_END_ALLOW_THREADS 378 fd_is_own = 1; 379 if (self->fd < 0) { 380 #ifdef MS_WINDOWS 381 if (widename != NULL) 382 PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError, widename); 383 else 384 #endif 385 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name); 386 goto error; 387 } 388 } 389 if (dircheck(self, nameobj) < 0) 390 goto error; 391 392 if (PyObject_SetAttrString((PyObject *)self, "name", nameobj) < 0) 393 goto error; 394 395 if (self->appending) { 396 /* For consistent behaviour, we explicitly seek to the 397 end of file (otherwise, it might be done only on the 398 first write()). */ 399 PyObject *pos = portable_lseek(self->fd, NULL, 2); 400 if (pos == NULL) 401 goto error; 402 Py_DECREF(pos); 403 } 404 405 goto done; 406 407 error: 408 if (!fd_is_own) 409 self->fd = -1; 410 411 ret = -1; 412 413 done: 414 Py_CLEAR(stringobj); 415 return ret; 416 } 417 418 static int 419 fileio_traverse(fileio *self, visitproc visit, void *arg) 420 { 421 Py_VISIT(self->dict); 422 return 0; 423 } 424 425 static int 426 fileio_clear(fileio *self) 427 { 428 Py_CLEAR(self->dict); 429 return 0; 430 } 431 432 static void 433 fileio_dealloc(fileio *self) 434 { 435 if (_PyIOBase_finalize((PyObject *) self) < 0) 436 return; 437 _PyObject_GC_UNTRACK(self); 438 if (self->weakreflist != NULL) 439 PyObject_ClearWeakRefs((PyObject *) self); 440 Py_CLEAR(self->dict); 441 Py_TYPE(self)->tp_free((PyObject *)self); 442 } 443 444 static PyObject * 445 err_closed(void) 446 { 447 PyErr_SetString(PyExc_ValueError, "I/O operation on closed file"); 448 return NULL; 449 } 450 451 static PyObject * 452 err_mode(char *action) 453 { 454 PyErr_Format(PyExc_ValueError, "File not open for %s", action); 455 return NULL; 456 } 457 458 static PyObject * 459 fileio_fileno(fileio *self) 460 { 461 if (self->fd < 0) 462 return err_closed(); 463 return PyInt_FromLong((long) self->fd); 464 } 465 466 static PyObject * 467 fileio_readable(fileio *self) 468 { 469 if (self->fd < 0) 470 return err_closed(); 471 return PyBool_FromLong((long) self->readable); 472 } 473 474 static PyObject * 475 fileio_writable(fileio *self) 476 { 477 if (self->fd < 0) 478 return err_closed(); 479 return PyBool_FromLong((long) self->writable); 480 } 481 482 static PyObject * 483 fileio_seekable(fileio *self) 484 { 485 if (self->fd < 0) 486 return err_closed(); 487 if (self->seekable < 0) { 488 PyObject *pos = portable_lseek(self->fd, NULL, SEEK_CUR); 489 if (pos == NULL) { 490 PyErr_Clear(); 491 self->seekable = 0; 492 } else { 493 Py_DECREF(pos); 494 self->seekable = 1; 495 } 496 } 497 return PyBool_FromLong((long) self->seekable); 498 } 499 500 static PyObject * 501 fileio_readinto(fileio *self, PyObject *args) 502 { 503 Py_buffer pbuf; 504 Py_ssize_t n, len; 505 506 if (self->fd < 0) 507 return err_closed(); 508 if (!self->readable) 509 return err_mode("reading"); 510 511 if (!PyArg_ParseTuple(args, "w*", &pbuf)) 512 return NULL; 513 514 if (_PyVerify_fd(self->fd)) { 515 len = pbuf.len; 516 Py_BEGIN_ALLOW_THREADS 517 errno = 0; 518 #if defined(MS_WIN64) || defined(MS_WINDOWS) 519 if (len > INT_MAX) 520 len = INT_MAX; 521 n = read(self->fd, pbuf.buf, (int)len); 522 #else 523 n = read(self->fd, pbuf.buf, len); 524 #endif 525 Py_END_ALLOW_THREADS 526 } else 527 n = -1; 528 PyBuffer_Release(&pbuf); 529 if (n < 0) { 530 if (errno == EAGAIN) 531 Py_RETURN_NONE; 532 PyErr_SetFromErrno(PyExc_IOError); 533 return NULL; 534 } 535 536 return PyLong_FromSsize_t(n); 537 } 538 539 static size_t 540 new_buffersize(fileio *self, size_t currentsize) 541 { 542 #ifdef HAVE_FSTAT 543 off_t pos, end; 544 struct stat st; 545 int res; 546 547 Py_BEGIN_ALLOW_THREADS 548 res = fstat(self->fd, &st); 549 Py_END_ALLOW_THREADS 550 551 if (res == 0) { 552 end = st.st_size; 553 554 Py_BEGIN_ALLOW_THREADS 555 pos = lseek(self->fd, 0L, SEEK_CUR); 556 Py_END_ALLOW_THREADS 557 558 /* Files claiming a size smaller than SMALLCHUNK may 559 actually be streaming pseudo-files. In this case, we 560 apply the more aggressive algorithm below. 561 */ 562 if (end >= SMALLCHUNK && end >= pos && pos >= 0) { 563 /* Add 1 so if the file were to grow we'd notice. */ 564 return currentsize + end - pos + 1; 565 } 566 } 567 #endif 568 /* Expand the buffer by an amount proportional to the current size, 569 giving us amortized linear-time behavior. Use a less-than-double 570 growth factor to avoid excessive allocation. */ 571 return currentsize + (currentsize >> 3) + 6; 572 } 573 574 static PyObject * 575 fileio_readall(fileio *self) 576 { 577 PyObject *result; 578 Py_ssize_t total = 0; 579 Py_ssize_t n; 580 581 if (self->fd < 0) 582 return err_closed(); 583 if (!_PyVerify_fd(self->fd)) 584 return PyErr_SetFromErrno(PyExc_IOError); 585 586 result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK); 587 if (result == NULL) 588 return NULL; 589 590 while (1) { 591 size_t newsize = new_buffersize(self, total); 592 if (newsize > PY_SSIZE_T_MAX || newsize <= 0) { 593 PyErr_SetString(PyExc_OverflowError, 594 "unbounded read returned more bytes " 595 "than a Python string can hold "); 596 Py_DECREF(result); 597 return NULL; 598 } 599 600 if (PyBytes_GET_SIZE(result) < (Py_ssize_t)newsize) { 601 if (_PyBytes_Resize(&result, newsize) < 0) 602 return NULL; /* result has been freed */ 603 } 604 Py_BEGIN_ALLOW_THREADS 605 errno = 0; 606 n = newsize - total; 607 #if defined(MS_WIN64) || defined(MS_WINDOWS) 608 if (n > INT_MAX) 609 n = INT_MAX; 610 n = read(self->fd, 611 PyBytes_AS_STRING(result) + total, 612 (int)n); 613 #else 614 n = read(self->fd, 615 PyBytes_AS_STRING(result) + total, 616 n); 617 #endif 618 Py_END_ALLOW_THREADS 619 if (n == 0) 620 break; 621 if (n < 0) { 622 if (errno == EINTR) { 623 if (PyErr_CheckSignals()) { 624 Py_DECREF(result); 625 return NULL; 626 } 627 continue; 628 } 629 if (errno == EAGAIN) { 630 if (total > 0) 631 break; 632 Py_DECREF(result); 633 Py_RETURN_NONE; 634 } 635 Py_DECREF(result); 636 PyErr_SetFromErrno(PyExc_IOError); 637 return NULL; 638 } 639 total += n; 640 } 641 642 if (PyBytes_GET_SIZE(result) > total) { 643 if (_PyBytes_Resize(&result, total) < 0) { 644 /* This should never happen, but just in case */ 645 return NULL; 646 } 647 } 648 return result; 649 } 650 651 static PyObject * 652 fileio_read(fileio *self, PyObject *args) 653 { 654 char *ptr; 655 Py_ssize_t n; 656 Py_ssize_t size = -1; 657 PyObject *bytes; 658 659 if (self->fd < 0) 660 return err_closed(); 661 if (!self->readable) 662 return err_mode("reading"); 663 664 if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size)) 665 return NULL; 666 667 if (size < 0) { 668 return fileio_readall(self); 669 } 670 671 #if defined(MS_WIN64) || defined(MS_WINDOWS) 672 if (size > INT_MAX) 673 size = INT_MAX; 674 #endif 675 bytes = PyBytes_FromStringAndSize(NULL, size); 676 if (bytes == NULL) 677 return NULL; 678 ptr = PyBytes_AS_STRING(bytes); 679 680 if (_PyVerify_fd(self->fd)) { 681 Py_BEGIN_ALLOW_THREADS 682 errno = 0; 683 #if defined(MS_WIN64) || defined(MS_WINDOWS) 684 n = read(self->fd, ptr, (int)size); 685 #else 686 n = read(self->fd, ptr, size); 687 #endif 688 Py_END_ALLOW_THREADS 689 } else 690 n = -1; 691 692 if (n < 0) { 693 Py_DECREF(bytes); 694 if (errno == EAGAIN) 695 Py_RETURN_NONE; 696 PyErr_SetFromErrno(PyExc_IOError); 697 return NULL; 698 } 699 700 if (n != size) { 701 if (_PyBytes_Resize(&bytes, n) < 0) 702 return NULL; 703 } 704 705 return (PyObject *) bytes; 706 } 707 708 static PyObject * 709 fileio_write(fileio *self, PyObject *args) 710 { 711 Py_buffer pbuf; 712 Py_ssize_t n, len; 713 714 if (self->fd < 0) 715 return err_closed(); 716 if (!self->writable) 717 return err_mode("writing"); 718 719 if (!PyArg_ParseTuple(args, "s*", &pbuf)) 720 return NULL; 721 722 if (_PyVerify_fd(self->fd)) { 723 Py_BEGIN_ALLOW_THREADS 724 errno = 0; 725 len = pbuf.len; 726 #if defined(MS_WIN64) || defined(MS_WINDOWS) 727 if (len > INT_MAX) 728 len = INT_MAX; 729 n = write(self->fd, pbuf.buf, (int)len); 730 #else 731 n = write(self->fd, pbuf.buf, len); 732 #endif 733 Py_END_ALLOW_THREADS 734 } else 735 n = -1; 736 737 PyBuffer_Release(&pbuf); 738 739 if (n < 0) { 740 if (errno == EAGAIN) 741 Py_RETURN_NONE; 742 PyErr_SetFromErrno(PyExc_IOError); 743 return NULL; 744 } 745 746 return PyLong_FromSsize_t(n); 747 } 748 749 /* XXX Windows support below is likely incomplete */ 750 751 /* Cribbed from posix_lseek() */ 752 static PyObject * 753 portable_lseek(int fd, PyObject *posobj, int whence) 754 { 755 Py_off_t pos, res; 756 757 #ifdef SEEK_SET 758 /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */ 759 switch (whence) { 760 #if SEEK_SET != 0 761 case 0: whence = SEEK_SET; break; 762 #endif 763 #if SEEK_CUR != 1 764 case 1: whence = SEEK_CUR; break; 765 #endif 766 #if SEEK_END != 2 767 case 2: whence = SEEK_END; break; 768 #endif 769 } 770 #endif /* SEEK_SET */ 771 772 if (posobj == NULL) 773 pos = 0; 774 else { 775 if(PyFloat_Check(posobj)) { 776 PyErr_SetString(PyExc_TypeError, "an integer is required"); 777 return NULL; 778 } 779 #if defined(HAVE_LARGEFILE_SUPPORT) 780 pos = PyLong_AsLongLong(posobj); 781 #else 782 pos = PyLong_AsLong(posobj); 783 #endif 784 if (PyErr_Occurred()) 785 return NULL; 786 } 787 788 if (_PyVerify_fd(fd)) { 789 Py_BEGIN_ALLOW_THREADS 790 #if defined(MS_WIN64) || defined(MS_WINDOWS) 791 res = _lseeki64(fd, pos, whence); 792 #else 793 res = lseek(fd, pos, whence); 794 #endif 795 Py_END_ALLOW_THREADS 796 } else 797 res = -1; 798 if (res < 0) 799 return PyErr_SetFromErrno(PyExc_IOError); 800 801 #if defined(HAVE_LARGEFILE_SUPPORT) 802 return PyLong_FromLongLong(res); 803 #else 804 return PyLong_FromLong(res); 805 #endif 806 } 807 808 static PyObject * 809 fileio_seek(fileio *self, PyObject *args) 810 { 811 PyObject *posobj; 812 int whence = 0; 813 814 if (self->fd < 0) 815 return err_closed(); 816 817 if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence)) 818 return NULL; 819 820 return portable_lseek(self->fd, posobj, whence); 821 } 822 823 static PyObject * 824 fileio_tell(fileio *self, PyObject *args) 825 { 826 if (self->fd < 0) 827 return err_closed(); 828 829 return portable_lseek(self->fd, NULL, 1); 830 } 831 832 #ifdef HAVE_FTRUNCATE 833 static PyObject * 834 fileio_truncate(fileio *self, PyObject *args) 835 { 836 PyObject *posobj = NULL; /* the new size wanted by the user */ 837 #ifndef MS_WINDOWS 838 Py_off_t pos; 839 #endif 840 int ret; 841 int fd; 842 843 fd = self->fd; 844 if (fd < 0) 845 return err_closed(); 846 if (!self->writable) 847 return err_mode("writing"); 848 849 if (!PyArg_ParseTuple(args, "|O", &posobj)) 850 return NULL; 851 852 if (posobj == Py_None || posobj == NULL) { 853 /* Get the current position. */ 854 posobj = portable_lseek(fd, NULL, 1); 855 if (posobj == NULL) 856 return NULL; 857 } 858 else { 859 Py_INCREF(posobj); 860 } 861 862 #ifdef MS_WINDOWS 863 /* MS _chsize doesn't work if newsize doesn't fit in 32 bits, 864 so don't even try using it. */ 865 { 866 PyObject *oldposobj, *tempposobj; 867 HANDLE hFile; 868 869 /* we save the file pointer position */ 870 oldposobj = portable_lseek(fd, NULL, 1); 871 if (oldposobj == NULL) { 872 Py_DECREF(posobj); 873 return NULL; 874 } 875 876 /* we then move to the truncation position */ 877 tempposobj = portable_lseek(fd, posobj, 0); 878 if (tempposobj == NULL) { 879 Py_DECREF(oldposobj); 880 Py_DECREF(posobj); 881 return NULL; 882 } 883 Py_DECREF(tempposobj); 884 885 /* Truncate. Note that this may grow the file! */ 886 Py_BEGIN_ALLOW_THREADS 887 errno = 0; 888 hFile = (HANDLE)_get_osfhandle(fd); 889 ret = hFile == (HANDLE)-1; /* testing for INVALID_HANDLE value */ 890 if (ret == 0) { 891 ret = SetEndOfFile(hFile) == 0; 892 if (ret) 893 errno = EACCES; 894 } 895 Py_END_ALLOW_THREADS 896 897 /* we restore the file pointer position in any case */ 898 tempposobj = portable_lseek(fd, oldposobj, 0); 899 Py_DECREF(oldposobj); 900 if (tempposobj == NULL) { 901 Py_DECREF(posobj); 902 return NULL; 903 } 904 Py_DECREF(tempposobj); 905 } 906 #else 907 908 #if defined(HAVE_LARGEFILE_SUPPORT) 909 pos = PyLong_AsLongLong(posobj); 910 #else 911 pos = PyLong_AsLong(posobj); 912 #endif 913 if (PyErr_Occurred()){ 914 Py_DECREF(posobj); 915 return NULL; 916 } 917 918 Py_BEGIN_ALLOW_THREADS 919 errno = 0; 920 ret = ftruncate(fd, pos); 921 Py_END_ALLOW_THREADS 922 923 #endif /* !MS_WINDOWS */ 924 925 if (ret != 0) { 926 Py_DECREF(posobj); 927 PyErr_SetFromErrno(PyExc_IOError); 928 return NULL; 929 } 930 931 return posobj; 932 } 933 #endif /* HAVE_FTRUNCATE */ 934 935 static char * 936 mode_string(fileio *self) 937 { 938 if (self->appending) { 939 if (self->readable) 940 return "ab+"; 941 else 942 return "ab"; 943 } 944 else if (self->readable) { 945 if (self->writable) 946 return "rb+"; 947 else 948 return "rb"; 949 } 950 else 951 return "wb"; 952 } 953 954 static PyObject * 955 fileio_repr(fileio *self) 956 { 957 PyObject *nameobj, *res; 958 959 if (self->fd < 0) 960 return PyString_FromFormat("<_io.FileIO [closed]>"); 961 962 nameobj = PyObject_GetAttrString((PyObject *) self, "name"); 963 if (nameobj == NULL) { 964 if (PyErr_ExceptionMatches(PyExc_AttributeError)) 965 PyErr_Clear(); 966 else 967 return NULL; 968 res = PyString_FromFormat("<_io.FileIO fd=%d mode='%s'>", 969 self->fd, mode_string(self)); 970 } 971 else { 972 PyObject *repr = PyObject_Repr(nameobj); 973 Py_DECREF(nameobj); 974 if (repr == NULL) 975 return NULL; 976 res = PyString_FromFormat("<_io.FileIO name=%s mode='%s'>", 977 PyString_AS_STRING(repr), 978 mode_string(self)); 979 Py_DECREF(repr); 980 } 981 return res; 982 } 983 984 static PyObject * 985 fileio_isatty(fileio *self) 986 { 987 long res; 988 989 if (self->fd < 0) 990 return err_closed(); 991 Py_BEGIN_ALLOW_THREADS 992 res = isatty(self->fd); 993 Py_END_ALLOW_THREADS 994 return PyBool_FromLong(res); 995 } 996 997 998 PyDoc_STRVAR(fileio_doc, 999 "file(name: str[, mode: str]) -> file IO object\n" 1000 "\n" 1001 "Open a file. The mode can be 'r' (default), 'w' or 'a' for reading,\n" 1002 "writing or appending. The file will be created if it doesn't exist\n" 1003 "when opened for writing or appending; it will be truncated when\n" 1004 "opened for writing. Add a '+' to the mode to allow simultaneous\n" 1005 "reading and writing."); 1006 1007 PyDoc_STRVAR(read_doc, 1008 "read(size: int) -> bytes. read at most size bytes, returned as bytes.\n" 1009 "\n" 1010 "Only makes one system call, so less data may be returned than requested\n" 1011 "In non-blocking mode, returns None if no data is available.\n" 1012 "On end-of-file, returns ''."); 1013 1014 PyDoc_STRVAR(readall_doc, 1015 "readall() -> bytes. read all data from the file, returned as bytes.\n" 1016 "\n" 1017 "In non-blocking mode, returns as much as is immediately available,\n" 1018 "or None if no data is available. On end-of-file, returns ''."); 1019 1020 PyDoc_STRVAR(write_doc, 1021 "write(b) -> int. Write array of bytes b, return number written.\n" 1022 "\n" 1023 "Only makes one system call, so not all of the data may be written.\n" 1024 "The number of bytes actually written is returned. In non-blocking mode,\n" 1025 "returns None if the write would block." 1026 ); 1027 1028 PyDoc_STRVAR(fileno_doc, 1029 "fileno() -> int. Return the underlying file descriptor (an integer)."); 1030 1031 PyDoc_STRVAR(seek_doc, 1032 "seek(offset: int[, whence: int]) -> int. Move to new file position\n" 1033 "and return the file position.\n" 1034 "\n" 1035 "Argument offset is a byte count. Optional argument whence defaults to\n" 1036 "SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values\n" 1037 "are SEEK_CUR or 1 (move relative to current position, positive or negative),\n" 1038 "and SEEK_END or 2 (move relative to end of file, usually negative, although\n" 1039 "many platforms allow seeking beyond the end of a file).\n" 1040 "\n" 1041 "Note that not all file objects are seekable."); 1042 1043 #ifdef HAVE_FTRUNCATE 1044 PyDoc_STRVAR(truncate_doc, 1045 "truncate([size: int]) -> int. Truncate the file to at most size bytes and\n" 1046 "return the truncated size.\n" 1047 "\n" 1048 "Size defaults to the current file position, as returned by tell().\n" 1049 "The current file position is changed to the value of size."); 1050 #endif 1051 1052 PyDoc_STRVAR(tell_doc, 1053 "tell() -> int. Current file position.\n" 1054 "\n" 1055 "Can raise OSError for non seekable files." 1056 ); 1057 1058 PyDoc_STRVAR(readinto_doc, 1059 "readinto() -> Same as RawIOBase.readinto()."); 1060 1061 PyDoc_STRVAR(close_doc, 1062 "close() -> None. Close the file.\n" 1063 "\n" 1064 "A closed file cannot be used for further I/O operations. close() may be\n" 1065 "called more than once without error."); 1066 1067 PyDoc_STRVAR(isatty_doc, 1068 "isatty() -> bool. True if the file is connected to a TTY device."); 1069 1070 PyDoc_STRVAR(seekable_doc, 1071 "seekable() -> bool. True if file supports random-access."); 1072 1073 PyDoc_STRVAR(readable_doc, 1074 "readable() -> bool. True if file was opened in a read mode."); 1075 1076 PyDoc_STRVAR(writable_doc, 1077 "writable() -> bool. True if file was opened in a write mode."); 1078 1079 static PyMethodDef fileio_methods[] = { 1080 {"read", (PyCFunction)fileio_read, METH_VARARGS, read_doc}, 1081 {"readall", (PyCFunction)fileio_readall, METH_NOARGS, readall_doc}, 1082 {"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc}, 1083 {"write", (PyCFunction)fileio_write, METH_VARARGS, write_doc}, 1084 {"seek", (PyCFunction)fileio_seek, METH_VARARGS, seek_doc}, 1085 {"tell", (PyCFunction)fileio_tell, METH_VARARGS, tell_doc}, 1086 #ifdef HAVE_FTRUNCATE 1087 {"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc}, 1088 #endif 1089 {"close", (PyCFunction)fileio_close, METH_NOARGS, close_doc}, 1090 {"seekable", (PyCFunction)fileio_seekable, METH_NOARGS, seekable_doc}, 1091 {"readable", (PyCFunction)fileio_readable, METH_NOARGS, readable_doc}, 1092 {"writable", (PyCFunction)fileio_writable, METH_NOARGS, writable_doc}, 1093 {"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc}, 1094 {"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc}, 1095 {NULL, NULL} /* sentinel */ 1096 }; 1097 1098 /* 'closed' and 'mode' are attributes for backwards compatibility reasons. */ 1099 1100 static PyObject * 1101 get_closed(fileio *self, void *closure) 1102 { 1103 return PyBool_FromLong((long)(self->fd < 0)); 1104 } 1105 1106 static PyObject * 1107 get_closefd(fileio *self, void *closure) 1108 { 1109 return PyBool_FromLong((long)(self->closefd)); 1110 } 1111 1112 static PyObject * 1113 get_mode(fileio *self, void *closure) 1114 { 1115 return PyUnicode_FromString(mode_string(self)); 1116 } 1117 1118 static PyGetSetDef fileio_getsetlist[] = { 1119 {"closed", (getter)get_closed, NULL, "True if the file is closed"}, 1120 {"closefd", (getter)get_closefd, NULL, 1121 "True if the file descriptor will be closed by close()."}, 1122 {"mode", (getter)get_mode, NULL, "String giving the file mode"}, 1123 {NULL}, 1124 }; 1125 1126 PyTypeObject PyFileIO_Type = { 1127 PyVarObject_HEAD_INIT(NULL, 0) 1128 "_io.FileIO", 1129 sizeof(fileio), 1130 0, 1131 (destructor)fileio_dealloc, /* tp_dealloc */ 1132 0, /* tp_print */ 1133 0, /* tp_getattr */ 1134 0, /* tp_setattr */ 1135 0, /* tp_reserved */ 1136 (reprfunc)fileio_repr, /* tp_repr */ 1137 0, /* tp_as_number */ 1138 0, /* tp_as_sequence */ 1139 0, /* tp_as_mapping */ 1140 0, /* tp_hash */ 1141 0, /* tp_call */ 1142 0, /* tp_str */ 1143 PyObject_GenericGetAttr, /* tp_getattro */ 1144 0, /* tp_setattro */ 1145 0, /* tp_as_buffer */ 1146 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE 1147 | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 1148 fileio_doc, /* tp_doc */ 1149 (traverseproc)fileio_traverse, /* tp_traverse */ 1150 (inquiry)fileio_clear, /* tp_clear */ 1151 0, /* tp_richcompare */ 1152 offsetof(fileio, weakreflist), /* tp_weaklistoffset */ 1153 0, /* tp_iter */ 1154 0, /* tp_iternext */ 1155 fileio_methods, /* tp_methods */ 1156 0, /* tp_members */ 1157 fileio_getsetlist, /* tp_getset */ 1158 0, /* tp_base */ 1159 0, /* tp_dict */ 1160 0, /* tp_descr_get */ 1161 0, /* tp_descr_set */ 1162 offsetof(fileio, dict), /* tp_dictoffset */ 1163 fileio_init, /* tp_init */ 1164 PyType_GenericAlloc, /* tp_alloc */ 1165 fileio_new, /* tp_new */ 1166 PyObject_GC_Del, /* tp_free */ 1167 }; 1168