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