Home | History | Annotate | Download | only in _io
      1 /* Author: Daniel Stutzbach */
      2 
      3 #define PY_SSIZE_T_CLEAN
      4 #include "Python.h"
      5 #include "structmember.h"
      6 #ifdef HAVE_SYS_TYPES_H
      7 #include <sys/types.h>
      8 #endif
      9 #ifdef HAVE_SYS_STAT_H
     10 #include <sys/stat.h>
     11 #endif
     12 #ifdef HAVE_IO_H
     13 #include <io.h>
     14 #endif
     15 #ifdef HAVE_FCNTL_H
     16 #include <fcntl.h>
     17 #endif
     18 #include <stddef.h> /* For offsetof */
     19 #include "_iomodule.h"
     20 
     21 /*
     22  * Known likely problems:
     23  *
     24  * - Files larger then 2**32-1
     25  * - Files with unicode filenames
     26  * - Passing numbers greater than 2**32-1 when an integer is expected
     27  * - Making it work on Windows and other oddball platforms
     28  *
     29  * To Do:
     30  *
     31  * - autoconfify header file inclusion
     32  */
     33 
     34 #ifdef MS_WINDOWS
     35 /* can simulate truncate with Win32 API functions; see file_truncate */
     36 #define HAVE_FTRUNCATE
     37 #define WIN32_LEAN_AND_MEAN
     38 #include <windows.h>
     39 #endif
     40 
     41 #if BUFSIZ < (8*1024)
     42 #define SMALLCHUNK (8*1024)
     43 #elif (BUFSIZ >= (2 << 25))
     44 #error "unreasonable BUFSIZ > 64MB defined"
     45 #else
     46 #define SMALLCHUNK BUFSIZ
     47 #endif
     48 
     49 /*[clinic input]
     50 module _io
     51 class _io.FileIO "fileio *" "&PyFileIO_Type"
     52 [clinic start generated code]*/
     53 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=1c77708b41fda70c]*/
     54 
     55 /*[python input]
     56 class io_ssize_t_converter(CConverter):
     57     type = 'Py_ssize_t'
     58     converter = '_PyIO_ConvertSsize_t'
     59 [python start generated code]*/
     60 /*[python end generated code: output=da39a3ee5e6b4b0d input=d0a811d3cbfd1b33]*/
     61 
     62 typedef struct {
     63     PyObject_HEAD
     64     int fd;
     65     unsigned int created : 1;
     66     unsigned int readable : 1;
     67     unsigned int writable : 1;
     68     unsigned int appending : 1;
     69     signed int seekable : 2; /* -1 means unknown */
     70     unsigned int closefd : 1;
     71     char finalizing;
     72     unsigned int blksize;
     73     PyObject *weakreflist;
     74     PyObject *dict;
     75 } fileio;
     76 
     77 PyTypeObject PyFileIO_Type;
     78 
     79 _Py_IDENTIFIER(name);
     80 
     81 #define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type))
     82 
     83 int
     84 _PyFileIO_closed(PyObject *self)
     85 {
     86     return ((fileio *)self)->fd < 0;
     87 }
     88 
     89 /* Because this can call arbitrary code, it shouldn't be called when
     90    the refcount is 0 (that is, not directly from tp_dealloc unless
     91    the refcount has been temporarily re-incremented). */
     92 static PyObject *
     93 fileio_dealloc_warn(fileio *self, PyObject *source)
     94 {
     95     if (self->fd >= 0 && self->closefd) {
     96         PyObject *exc, *val, *tb;
     97         PyErr_Fetch(&exc, &val, &tb);
     98         if (PyErr_ResourceWarning(source, 1, "unclosed file %R", source)) {
     99             /* Spurious errors can appear at shutdown */
    100             if (PyErr_ExceptionMatches(PyExc_Warning))
    101                 PyErr_WriteUnraisable((PyObject *) self);
    102         }
    103         PyErr_Restore(exc, val, tb);
    104     }
    105     Py_RETURN_NONE;
    106 }
    107 
    108 static PyObject *
    109 portable_lseek(int fd, PyObject *posobj, int whence);
    110 
    111 static PyObject *portable_lseek(int fd, PyObject *posobj, int whence);
    112 
    113 /* Returns 0 on success, -1 with exception set on failure. */
    114 static int
    115 internal_close(fileio *self)
    116 {
    117     int err = 0;
    118     int save_errno = 0;
    119     if (self->fd >= 0) {
    120         int fd = self->fd;
    121         self->fd = -1;
    122         /* fd is accessible and someone else may have closed it */
    123         Py_BEGIN_ALLOW_THREADS
    124         _Py_BEGIN_SUPPRESS_IPH
    125         err = close(fd);
    126         if (err < 0)
    127             save_errno = errno;
    128         _Py_END_SUPPRESS_IPH
    129         Py_END_ALLOW_THREADS
    130     }
    131     if (err < 0) {
    132         errno = save_errno;
    133         PyErr_SetFromErrno(PyExc_IOError);
    134         return -1;
    135     }
    136     return 0;
    137 }
    138 
    139 /*[clinic input]
    140 _io.FileIO.close
    141 
    142 Close the file.
    143 
    144 A closed file cannot be used for further I/O operations.  close() may be
    145 called more than once without error.
    146 [clinic start generated code]*/
    147 
    148 static PyObject *
    149 _io_FileIO_close_impl(fileio *self)
    150 /*[clinic end generated code: output=7737a319ef3bad0b input=f35231760d54a522]*/
    151 {
    152     PyObject *res;
    153     PyObject *exc, *val, *tb;
    154     int rc;
    155     _Py_IDENTIFIER(close);
    156     res = _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type,
    157                                  &PyId_close, "O", self);
    158     if (!self->closefd) {
    159         self->fd = -1;
    160         return res;
    161     }
    162     if (res == NULL)
    163         PyErr_Fetch(&exc, &val, &tb);
    164     if (self->finalizing) {
    165         PyObject *r = fileio_dealloc_warn(self, (PyObject *) self);
    166         if (r)
    167             Py_DECREF(r);
    168         else
    169             PyErr_Clear();
    170     }
    171     rc = internal_close(self);
    172     if (res == NULL)
    173         _PyErr_ChainExceptions(exc, val, tb);
    174     if (rc < 0)
    175         Py_CLEAR(res);
    176     return res;
    177 }
    178 
    179 static PyObject *
    180 fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
    181 {
    182     fileio *self;
    183 
    184     assert(type != NULL && type->tp_alloc != NULL);
    185 
    186     self = (fileio *) type->tp_alloc(type, 0);
    187     if (self != NULL) {
    188         self->fd = -1;
    189         self->created = 0;
    190         self->readable = 0;
    191         self->writable = 0;
    192         self->appending = 0;
    193         self->seekable = -1;
    194         self->blksize = 0;
    195         self->closefd = 1;
    196         self->weakreflist = NULL;
    197     }
    198 
    199     return (PyObject *) self;
    200 }
    201 
    202 #ifdef O_CLOEXEC
    203 extern int _Py_open_cloexec_works;
    204 #endif
    205 
    206 /*[clinic input]
    207 _io.FileIO.__init__
    208     file as nameobj: object
    209     mode: str = "r"
    210     closefd: int(c_default="1") = True
    211     opener: object = None
    212 
    213 Open a file.
    214 
    215 The mode can be 'r' (default), 'w', 'x' or 'a' for reading,
    216 writing, exclusive creation or appending.  The file will be created if it
    217 doesn't exist when opened for writing or appending; it will be truncated
    218 when opened for writing.  A FileExistsError will be raised if it already
    219 exists when opened for creating. Opening a file for creating implies
    220 writing so this mode behaves in a similar way to 'w'.Add a '+' to the mode
    221 to allow simultaneous reading and writing. A custom opener can be used by
    222 passing a callable as *opener*. The underlying file descriptor for the file
    223 object is then obtained by calling opener with (*name*, *flags*).
    224 *opener* must return an open file descriptor (passing os.open as *opener*
    225 results in functionality similar to passing None).
    226 [clinic start generated code]*/
    227 
    228 static int
    229 _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode,
    230                          int closefd, PyObject *opener)
    231 /*[clinic end generated code: output=23413f68e6484bbd input=193164e293d6c097]*/
    232 {
    233 #ifdef MS_WINDOWS
    234     Py_UNICODE *widename = NULL;
    235 #else
    236     const char *name = NULL;
    237 #endif
    238     PyObject *stringobj = NULL;
    239     const char *s;
    240     int ret = 0;
    241     int rwa = 0, plus = 0;
    242     int flags = 0;
    243     int fd = -1;
    244     int fd_is_own = 0;
    245 #ifdef O_CLOEXEC
    246     int *atomic_flag_works = &_Py_open_cloexec_works;
    247 #elif !defined(MS_WINDOWS)
    248     int *atomic_flag_works = NULL;
    249 #endif
    250     struct _Py_stat_struct fdfstat;
    251     int fstat_result;
    252     int async_err = 0;
    253 
    254     assert(PyFileIO_Check(self));
    255     if (self->fd >= 0) {
    256         if (self->closefd) {
    257             /* Have to close the existing file first. */
    258             if (internal_close(self) < 0)
    259                 return -1;
    260         }
    261         else
    262             self->fd = -1;
    263     }
    264 
    265     if (PyFloat_Check(nameobj)) {
    266         PyErr_SetString(PyExc_TypeError,
    267                         "integer argument expected, got float");
    268         return -1;
    269     }
    270 
    271     fd = _PyLong_AsInt(nameobj);
    272     if (fd < 0) {
    273         if (!PyErr_Occurred()) {
    274             PyErr_SetString(PyExc_ValueError,
    275                             "negative file descriptor");
    276             return -1;
    277         }
    278         PyErr_Clear();
    279     }
    280 
    281     if (fd < 0) {
    282 #ifdef MS_WINDOWS
    283         Py_ssize_t length;
    284         if (!PyUnicode_FSDecoder(nameobj, &stringobj)) {
    285             return -1;
    286         }
    287         widename = PyUnicode_AsUnicodeAndSize(stringobj, &length);
    288         if (widename == NULL)
    289             return -1;
    290 #else
    291         if (!PyUnicode_FSConverter(nameobj, &stringobj)) {
    292             return -1;
    293         }
    294         name = PyBytes_AS_STRING(stringobj);
    295 #endif
    296     }
    297 
    298     s = mode;
    299     while (*s) {
    300         switch (*s++) {
    301         case 'x':
    302             if (rwa) {
    303             bad_mode:
    304                 PyErr_SetString(PyExc_ValueError,
    305                                 "Must have exactly one of create/read/write/append "
    306                                 "mode and at most one plus");
    307                 goto error;
    308             }
    309             rwa = 1;
    310             self->created = 1;
    311             self->writable = 1;
    312             flags |= O_EXCL | O_CREAT;
    313             break;
    314         case 'r':
    315             if (rwa)
    316                 goto bad_mode;
    317             rwa = 1;
    318             self->readable = 1;
    319             break;
    320         case 'w':
    321             if (rwa)
    322                 goto bad_mode;
    323             rwa = 1;
    324             self->writable = 1;
    325             flags |= O_CREAT | O_TRUNC;
    326             break;
    327         case 'a':
    328             if (rwa)
    329                 goto bad_mode;
    330             rwa = 1;
    331             self->writable = 1;
    332             self->appending = 1;
    333             flags |= O_APPEND | O_CREAT;
    334             break;
    335         case 'b':
    336             break;
    337         case '+':
    338             if (plus)
    339                 goto bad_mode;
    340             self->readable = self->writable = 1;
    341             plus = 1;
    342             break;
    343         default:
    344             PyErr_Format(PyExc_ValueError,
    345                          "invalid mode: %.200s", mode);
    346             goto error;
    347         }
    348     }
    349 
    350     if (!rwa)
    351         goto bad_mode;
    352 
    353     if (self->readable && self->writable)
    354         flags |= O_RDWR;
    355     else if (self->readable)
    356         flags |= O_RDONLY;
    357     else
    358         flags |= O_WRONLY;
    359 
    360 #ifdef O_BINARY
    361     flags |= O_BINARY;
    362 #endif
    363 
    364 #ifdef MS_WINDOWS
    365     flags |= O_NOINHERIT;
    366 #elif defined(O_CLOEXEC)
    367     flags |= O_CLOEXEC;
    368 #endif
    369 
    370     if (fd >= 0) {
    371         self->fd = fd;
    372         self->closefd = closefd;
    373     }
    374     else {
    375         self->closefd = 1;
    376         if (!closefd) {
    377             PyErr_SetString(PyExc_ValueError,
    378                 "Cannot use closefd=False with file name");
    379             goto error;
    380         }
    381 
    382         errno = 0;
    383         if (opener == Py_None) {
    384             do {
    385                 Py_BEGIN_ALLOW_THREADS
    386 #ifdef MS_WINDOWS
    387                 self->fd = _wopen(widename, flags, 0666);
    388 #else
    389                 self->fd = open(name, flags, 0666);
    390 #endif
    391                 Py_END_ALLOW_THREADS
    392             } while (self->fd < 0 && errno == EINTR &&
    393                      !(async_err = PyErr_CheckSignals()));
    394 
    395             if (async_err)
    396                 goto error;
    397         }
    398         else {
    399             PyObject *fdobj;
    400 
    401 #ifndef MS_WINDOWS
    402             /* the opener may clear the atomic flag */
    403             atomic_flag_works = NULL;
    404 #endif
    405 
    406             fdobj = PyObject_CallFunction(opener, "Oi", nameobj, flags);
    407             if (fdobj == NULL)
    408                 goto error;
    409             if (!PyLong_Check(fdobj)) {
    410                 Py_DECREF(fdobj);
    411                 PyErr_SetString(PyExc_TypeError,
    412                         "expected integer from opener");
    413                 goto error;
    414             }
    415 
    416             self->fd = _PyLong_AsInt(fdobj);
    417             Py_DECREF(fdobj);
    418             if (self->fd < 0) {
    419                 if (!PyErr_Occurred()) {
    420                     /* The opener returned a negative but didn't set an
    421                        exception.  See issue #27066 */
    422                     PyErr_Format(PyExc_ValueError,
    423                                  "opener returned %d", self->fd);
    424                 }
    425                 goto error;
    426             }
    427         }
    428 
    429         fd_is_own = 1;
    430         if (self->fd < 0) {
    431             PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
    432             goto error;
    433         }
    434 
    435 #ifndef MS_WINDOWS
    436         if (_Py_set_inheritable(self->fd, 0, atomic_flag_works) < 0)
    437             goto error;
    438 #endif
    439     }
    440 
    441     self->blksize = DEFAULT_BUFFER_SIZE;
    442     Py_BEGIN_ALLOW_THREADS
    443     fstat_result = _Py_fstat_noraise(self->fd, &fdfstat);
    444     Py_END_ALLOW_THREADS
    445     if (fstat_result < 0) {
    446         /* Tolerate fstat() errors other than EBADF.  See Issue #25717, where
    447         an anonymous file on a Virtual Box shared folder filesystem would
    448         raise ENOENT. */
    449 #ifdef MS_WINDOWS
    450         if (GetLastError() == ERROR_INVALID_HANDLE) {
    451             PyErr_SetFromWindowsErr(0);
    452 #else
    453         if (errno == EBADF) {
    454             PyErr_SetFromErrno(PyExc_OSError);
    455 #endif
    456             goto error;
    457         }
    458     }
    459     else {
    460 #if defined(S_ISDIR) && defined(EISDIR)
    461         /* On Unix, open will succeed for directories.
    462            In Python, there should be no file objects referring to
    463            directories, so we need a check.  */
    464         if (S_ISDIR(fdfstat.st_mode)) {
    465             errno = EISDIR;
    466             PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj);
    467             goto error;
    468         }
    469 #endif /* defined(S_ISDIR) */
    470 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
    471         if (fdfstat.st_blksize > 1)
    472             self->blksize = fdfstat.st_blksize;
    473 #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
    474     }
    475 
    476 #if defined(MS_WINDOWS) || defined(__CYGWIN__)
    477     /* don't translate newlines (\r\n <=> \n) */
    478     _setmode(self->fd, O_BINARY);
    479 #endif
    480 
    481     if (_PyObject_SetAttrId((PyObject *)self, &PyId_name, nameobj) < 0)
    482         goto error;
    483 
    484     if (self->appending) {
    485         /* For consistent behaviour, we explicitly seek to the
    486            end of file (otherwise, it might be done only on the
    487            first write()). */
    488         PyObject *pos = portable_lseek(self->fd, NULL, 2);
    489         if (pos == NULL)
    490             goto error;
    491         Py_DECREF(pos);
    492     }
    493 
    494     goto done;
    495 
    496  error:
    497     ret = -1;
    498     if (!fd_is_own)
    499         self->fd = -1;
    500     if (self->fd >= 0)
    501         internal_close(self);
    502 
    503  done:
    504     Py_CLEAR(stringobj);
    505     return ret;
    506 }
    507 
    508 static int
    509 fileio_traverse(fileio *self, visitproc visit, void *arg)
    510 {
    511     Py_VISIT(self->dict);
    512     return 0;
    513 }
    514 
    515 static int
    516 fileio_clear(fileio *self)
    517 {
    518     Py_CLEAR(self->dict);
    519     return 0;
    520 }
    521 
    522 static void
    523 fileio_dealloc(fileio *self)
    524 {
    525     self->finalizing = 1;
    526     if (_PyIOBase_finalize((PyObject *) self) < 0)
    527         return;
    528     _PyObject_GC_UNTRACK(self);
    529     if (self->weakreflist != NULL)
    530         PyObject_ClearWeakRefs((PyObject *) self);
    531     Py_CLEAR(self->dict);
    532     Py_TYPE(self)->tp_free((PyObject *)self);
    533 }
    534 
    535 static PyObject *
    536 err_closed(void)
    537 {
    538     PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
    539     return NULL;
    540 }
    541 
    542 static PyObject *
    543 err_mode(const char *action)
    544 {
    545     _PyIO_State *state = IO_STATE();
    546     if (state != NULL)
    547         PyErr_Format(state->unsupported_operation,
    548                      "File not open for %s", action);
    549     return NULL;
    550 }
    551 
    552 /*[clinic input]
    553 _io.FileIO.fileno
    554 
    555 Return the underlying file descriptor (an integer).
    556 [clinic start generated code]*/
    557 
    558 static PyObject *
    559 _io_FileIO_fileno_impl(fileio *self)
    560 /*[clinic end generated code: output=a9626ce5398ece90 input=0b9b2de67335ada3]*/
    561 {
    562     if (self->fd < 0)
    563         return err_closed();
    564     return PyLong_FromLong((long) self->fd);
    565 }
    566 
    567 /*[clinic input]
    568 _io.FileIO.readable
    569 
    570 True if file was opened in a read mode.
    571 [clinic start generated code]*/
    572 
    573 static PyObject *
    574 _io_FileIO_readable_impl(fileio *self)
    575 /*[clinic end generated code: output=640744a6150fe9ba input=a3fdfed6eea721c5]*/
    576 {
    577     if (self->fd < 0)
    578         return err_closed();
    579     return PyBool_FromLong((long) self->readable);
    580 }
    581 
    582 /*[clinic input]
    583 _io.FileIO.writable
    584 
    585 True if file was opened in a write mode.
    586 [clinic start generated code]*/
    587 
    588 static PyObject *
    589 _io_FileIO_writable_impl(fileio *self)
    590 /*[clinic end generated code: output=96cefc5446e89977 input=c204a808ca2e1748]*/
    591 {
    592     if (self->fd < 0)
    593         return err_closed();
    594     return PyBool_FromLong((long) self->writable);
    595 }
    596 
    597 /*[clinic input]
    598 _io.FileIO.seekable
    599 
    600 True if file supports random-access.
    601 [clinic start generated code]*/
    602 
    603 static PyObject *
    604 _io_FileIO_seekable_impl(fileio *self)
    605 /*[clinic end generated code: output=47909ca0a42e9287 input=c8e5554d2fd63c7f]*/
    606 {
    607     if (self->fd < 0)
    608         return err_closed();
    609     if (self->seekable < 0) {
    610         PyObject *pos = portable_lseek(self->fd, NULL, SEEK_CUR);
    611         if (pos == NULL) {
    612             PyErr_Clear();
    613             self->seekable = 0;
    614         } else {
    615             Py_DECREF(pos);
    616             self->seekable = 1;
    617         }
    618     }
    619     return PyBool_FromLong((long) self->seekable);
    620 }
    621 
    622 /*[clinic input]
    623 _io.FileIO.readinto
    624     buffer: Py_buffer(accept={rwbuffer})
    625     /
    626 
    627 Same as RawIOBase.readinto().
    628 [clinic start generated code]*/
    629 
    630 static PyObject *
    631 _io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer)
    632 /*[clinic end generated code: output=b01a5a22c8415cb4 input=4721d7b68b154eaf]*/
    633 {
    634     Py_ssize_t n;
    635     int err;
    636 
    637     if (self->fd < 0)
    638         return err_closed();
    639     if (!self->readable)
    640         return err_mode("reading");
    641 
    642     n = _Py_read(self->fd, buffer->buf, buffer->len);
    643     /* copy errno because PyBuffer_Release() can indirectly modify it */
    644     err = errno;
    645 
    646     if (n == -1) {
    647         if (err == EAGAIN) {
    648             PyErr_Clear();
    649             Py_RETURN_NONE;
    650         }
    651         return NULL;
    652     }
    653 
    654     return PyLong_FromSsize_t(n);
    655 }
    656 
    657 static size_t
    658 new_buffersize(fileio *self, size_t currentsize)
    659 {
    660     size_t addend;
    661 
    662     /* Expand the buffer by an amount proportional to the current size,
    663        giving us amortized linear-time behavior.  For bigger sizes, use a
    664        less-than-double growth factor to avoid excessive allocation. */
    665     assert(currentsize <= PY_SSIZE_T_MAX);
    666     if (currentsize > 65536)
    667         addend = currentsize >> 3;
    668     else
    669         addend = 256 + currentsize;
    670     if (addend < SMALLCHUNK)
    671         /* Avoid tiny read() calls. */
    672         addend = SMALLCHUNK;
    673     return addend + currentsize;
    674 }
    675 
    676 /*[clinic input]
    677 _io.FileIO.readall
    678 
    679 Read all data from the file, returned as bytes.
    680 
    681 In non-blocking mode, returns as much as is immediately available,
    682 or None if no data is available.  Return an empty bytes object at EOF.
    683 [clinic start generated code]*/
    684 
    685 static PyObject *
    686 _io_FileIO_readall_impl(fileio *self)
    687 /*[clinic end generated code: output=faa0292b213b4022 input=dbdc137f55602834]*/
    688 {
    689     struct _Py_stat_struct status;
    690     Py_off_t pos, end;
    691     PyObject *result;
    692     Py_ssize_t bytes_read = 0;
    693     Py_ssize_t n;
    694     size_t bufsize;
    695 
    696     if (self->fd < 0)
    697         return err_closed();
    698 
    699     _Py_BEGIN_SUPPRESS_IPH
    700 #ifdef MS_WINDOWS
    701     pos = _lseeki64(self->fd, 0L, SEEK_CUR);
    702 #else
    703     pos = lseek(self->fd, 0L, SEEK_CUR);
    704 #endif
    705     _Py_END_SUPPRESS_IPH
    706 
    707     if (_Py_fstat_noraise(self->fd, &status) == 0)
    708         end = status.st_size;
    709     else
    710         end = (Py_off_t)-1;
    711 
    712     if (end > 0 && end >= pos && pos >= 0 && end - pos < PY_SSIZE_T_MAX) {
    713         /* This is probably a real file, so we try to allocate a
    714            buffer one byte larger than the rest of the file.  If the
    715            calculation is right then we should get EOF without having
    716            to enlarge the buffer. */
    717         bufsize = (size_t)(end - pos + 1);
    718     } else {
    719         bufsize = SMALLCHUNK;
    720     }
    721 
    722     result = PyBytes_FromStringAndSize(NULL, bufsize);
    723     if (result == NULL)
    724         return NULL;
    725 
    726     while (1) {
    727         if (bytes_read >= (Py_ssize_t)bufsize) {
    728             bufsize = new_buffersize(self, bytes_read);
    729             if (bufsize > PY_SSIZE_T_MAX || bufsize <= 0) {
    730                 PyErr_SetString(PyExc_OverflowError,
    731                                 "unbounded read returned more bytes "
    732                                 "than a Python bytes object can hold");
    733                 Py_DECREF(result);
    734                 return NULL;
    735             }
    736 
    737             if (PyBytes_GET_SIZE(result) < (Py_ssize_t)bufsize) {
    738                 if (_PyBytes_Resize(&result, bufsize) < 0)
    739                     return NULL;
    740             }
    741         }
    742 
    743         n = _Py_read(self->fd,
    744                      PyBytes_AS_STRING(result) + bytes_read,
    745                      bufsize - bytes_read);
    746 
    747         if (n == 0)
    748             break;
    749         if (n == -1) {
    750             if (errno == EAGAIN) {
    751                 PyErr_Clear();
    752                 if (bytes_read > 0)
    753                     break;
    754                 Py_DECREF(result);
    755                 Py_RETURN_NONE;
    756             }
    757             Py_DECREF(result);
    758             return NULL;
    759         }
    760         bytes_read += n;
    761         pos += n;
    762     }
    763 
    764     if (PyBytes_GET_SIZE(result) > bytes_read) {
    765         if (_PyBytes_Resize(&result, bytes_read) < 0)
    766             return NULL;
    767     }
    768     return result;
    769 }
    770 
    771 /*[clinic input]
    772 _io.FileIO.read
    773     size: io_ssize_t = -1
    774     /
    775 
    776 Read at most size bytes, returned as bytes.
    777 
    778 Only makes one system call, so less data may be returned than requested.
    779 In non-blocking mode, returns None if no data is available.
    780 Return an empty bytes object at EOF.
    781 [clinic start generated code]*/
    782 
    783 static PyObject *
    784 _io_FileIO_read_impl(fileio *self, Py_ssize_t size)
    785 /*[clinic end generated code: output=42528d39dd0ca641 input=5c6caa5490c13a9b]*/
    786 {
    787     char *ptr;
    788     Py_ssize_t n;
    789     PyObject *bytes;
    790 
    791     if (self->fd < 0)
    792         return err_closed();
    793     if (!self->readable)
    794         return err_mode("reading");
    795 
    796     if (size < 0)
    797         return _io_FileIO_readall_impl(self);
    798 
    799 #ifdef MS_WINDOWS
    800     /* On Windows, the count parameter of read() is an int */
    801     if (size > INT_MAX)
    802         size = INT_MAX;
    803 #endif
    804 
    805     bytes = PyBytes_FromStringAndSize(NULL, size);
    806     if (bytes == NULL)
    807         return NULL;
    808     ptr = PyBytes_AS_STRING(bytes);
    809 
    810     n = _Py_read(self->fd, ptr, size);
    811     if (n == -1) {
    812         /* copy errno because Py_DECREF() can indirectly modify it */
    813         int err = errno;
    814         Py_DECREF(bytes);
    815         if (err == EAGAIN) {
    816             PyErr_Clear();
    817             Py_RETURN_NONE;
    818         }
    819         return NULL;
    820     }
    821 
    822     if (n != size) {
    823         if (_PyBytes_Resize(&bytes, n) < 0) {
    824             Py_CLEAR(bytes);
    825             return NULL;
    826         }
    827     }
    828 
    829     return (PyObject *) bytes;
    830 }
    831 
    832 /*[clinic input]
    833 _io.FileIO.write
    834     b: Py_buffer
    835     /
    836 
    837 Write buffer b to file, return number of bytes written.
    838 
    839 Only makes one system call, so not all of the data may be written.
    840 The number of bytes actually written is returned.  In non-blocking mode,
    841 returns None if the write would block.
    842 [clinic start generated code]*/
    843 
    844 static PyObject *
    845 _io_FileIO_write_impl(fileio *self, Py_buffer *b)
    846 /*[clinic end generated code: output=b4059db3d363a2f7 input=6e7908b36f0ce74f]*/
    847 {
    848     Py_ssize_t n;
    849     int err;
    850 
    851     if (self->fd < 0)
    852         return err_closed();
    853     if (!self->writable)
    854         return err_mode("writing");
    855 
    856     n = _Py_write(self->fd, b->buf, b->len);
    857     /* copy errno because PyBuffer_Release() can indirectly modify it */
    858     err = errno;
    859 
    860     if (n < 0) {
    861         if (err == EAGAIN) {
    862             PyErr_Clear();
    863             Py_RETURN_NONE;
    864         }
    865         return NULL;
    866     }
    867 
    868     return PyLong_FromSsize_t(n);
    869 }
    870 
    871 /* XXX Windows support below is likely incomplete */
    872 
    873 /* Cribbed from posix_lseek() */
    874 static PyObject *
    875 portable_lseek(int fd, PyObject *posobj, int whence)
    876 {
    877     Py_off_t pos, res;
    878 
    879 #ifdef SEEK_SET
    880     /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
    881     switch (whence) {
    882 #if SEEK_SET != 0
    883     case 0: whence = SEEK_SET; break;
    884 #endif
    885 #if SEEK_CUR != 1
    886     case 1: whence = SEEK_CUR; break;
    887 #endif
    888 #if SEEK_END != 2
    889     case 2: whence = SEEK_END; break;
    890 #endif
    891     }
    892 #endif /* SEEK_SET */
    893 
    894     if (posobj == NULL)
    895         pos = 0;
    896     else {
    897         if(PyFloat_Check(posobj)) {
    898             PyErr_SetString(PyExc_TypeError, "an integer is required");
    899             return NULL;
    900         }
    901 #if defined(HAVE_LARGEFILE_SUPPORT)
    902         pos = PyLong_AsLongLong(posobj);
    903 #else
    904         pos = PyLong_AsLong(posobj);
    905 #endif
    906         if (PyErr_Occurred())
    907             return NULL;
    908     }
    909 
    910     Py_BEGIN_ALLOW_THREADS
    911     _Py_BEGIN_SUPPRESS_IPH
    912 #ifdef MS_WINDOWS
    913     res = _lseeki64(fd, pos, whence);
    914 #else
    915     res = lseek(fd, pos, whence);
    916 #endif
    917     _Py_END_SUPPRESS_IPH
    918     Py_END_ALLOW_THREADS
    919     if (res < 0)
    920         return PyErr_SetFromErrno(PyExc_IOError);
    921 
    922 #if defined(HAVE_LARGEFILE_SUPPORT)
    923     return PyLong_FromLongLong(res);
    924 #else
    925     return PyLong_FromLong(res);
    926 #endif
    927 }
    928 
    929 /*[clinic input]
    930 _io.FileIO.seek
    931     pos: object
    932     whence: int = 0
    933     /
    934 
    935 Move to new file position and return the file position.
    936 
    937 Argument offset is a byte count.  Optional argument whence defaults to
    938 SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values
    939 are SEEK_CUR or 1 (move relative to current position, positive or negative),
    940 and SEEK_END or 2 (move relative to end of file, usually negative, although
    941 many platforms allow seeking beyond the end of a file).
    942 
    943 Note that not all file objects are seekable.
    944 [clinic start generated code]*/
    945 
    946 static PyObject *
    947 _io_FileIO_seek_impl(fileio *self, PyObject *pos, int whence)
    948 /*[clinic end generated code: output=c976acdf054e6655 input=0439194b0774d454]*/
    949 {
    950     if (self->fd < 0)
    951         return err_closed();
    952 
    953     return portable_lseek(self->fd, pos, whence);
    954 }
    955 
    956 /*[clinic input]
    957 _io.FileIO.tell
    958 
    959 Current file position.
    960 
    961 Can raise OSError for non seekable files.
    962 [clinic start generated code]*/
    963 
    964 static PyObject *
    965 _io_FileIO_tell_impl(fileio *self)
    966 /*[clinic end generated code: output=ffe2147058809d0b input=807e24ead4cec2f9]*/
    967 {
    968     if (self->fd < 0)
    969         return err_closed();
    970 
    971     return portable_lseek(self->fd, NULL, 1);
    972 }
    973 
    974 #ifdef HAVE_FTRUNCATE
    975 /*[clinic input]
    976 _io.FileIO.truncate
    977     size as posobj: object = NULL
    978     /
    979 
    980 Truncate the file to at most size bytes and return the truncated size.
    981 
    982 Size defaults to the current file position, as returned by tell().
    983 The current file position is changed to the value of size.
    984 [clinic start generated code]*/
    985 
    986 static PyObject *
    987 _io_FileIO_truncate_impl(fileio *self, PyObject *posobj)
    988 /*[clinic end generated code: output=e49ca7a916c176fa input=9026af44686b7318]*/
    989 {
    990     Py_off_t pos;
    991     int ret;
    992     int fd;
    993 
    994     fd = self->fd;
    995     if (fd < 0)
    996         return err_closed();
    997     if (!self->writable)
    998         return err_mode("writing");
    999 
   1000     if (posobj == Py_None || posobj == NULL) {
   1001         /* Get the current position. */
   1002         posobj = portable_lseek(fd, NULL, 1);
   1003         if (posobj == NULL)
   1004             return NULL;
   1005     }
   1006     else {
   1007         Py_INCREF(posobj);
   1008     }
   1009 
   1010 #if defined(HAVE_LARGEFILE_SUPPORT)
   1011     pos = PyLong_AsLongLong(posobj);
   1012 #else
   1013     pos = PyLong_AsLong(posobj);
   1014 #endif
   1015     if (PyErr_Occurred()){
   1016         Py_DECREF(posobj);
   1017         return NULL;
   1018     }
   1019 
   1020     Py_BEGIN_ALLOW_THREADS
   1021     _Py_BEGIN_SUPPRESS_IPH
   1022     errno = 0;
   1023 #ifdef MS_WINDOWS
   1024     ret = _chsize_s(fd, pos);
   1025 #else
   1026     ret = ftruncate(fd, pos);
   1027 #endif
   1028     _Py_END_SUPPRESS_IPH
   1029     Py_END_ALLOW_THREADS
   1030 
   1031     if (ret != 0) {
   1032         Py_DECREF(posobj);
   1033         PyErr_SetFromErrno(PyExc_IOError);
   1034         return NULL;
   1035     }
   1036 
   1037     return posobj;
   1038 }
   1039 #endif /* HAVE_FTRUNCATE */
   1040 
   1041 static const char *
   1042 mode_string(fileio *self)
   1043 {
   1044     if (self->created) {
   1045         if (self->readable)
   1046             return "xb+";
   1047         else
   1048             return "xb";
   1049     }
   1050     if (self->appending) {
   1051         if (self->readable)
   1052             return "ab+";
   1053         else
   1054             return "ab";
   1055     }
   1056     else if (self->readable) {
   1057         if (self->writable)
   1058             return "rb+";
   1059         else
   1060             return "rb";
   1061     }
   1062     else
   1063         return "wb";
   1064 }
   1065 
   1066 static PyObject *
   1067 fileio_repr(fileio *self)
   1068 {
   1069     PyObject *nameobj, *res;
   1070 
   1071     if (self->fd < 0)
   1072         return PyUnicode_FromFormat("<_io.FileIO [closed]>");
   1073 
   1074     nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name);
   1075     if (nameobj == NULL) {
   1076         if (PyErr_ExceptionMatches(PyExc_AttributeError))
   1077             PyErr_Clear();
   1078         else
   1079             return NULL;
   1080         res = PyUnicode_FromFormat(
   1081             "<_io.FileIO fd=%d mode='%s' closefd=%s>",
   1082             self->fd, mode_string(self), self->closefd ? "True" : "False");
   1083     }
   1084     else {
   1085         res = PyUnicode_FromFormat(
   1086             "<_io.FileIO name=%R mode='%s' closefd=%s>",
   1087             nameobj, mode_string(self), self->closefd ? "True" : "False");
   1088         Py_DECREF(nameobj);
   1089     }
   1090     return res;
   1091 }
   1092 
   1093 /*[clinic input]
   1094 _io.FileIO.isatty
   1095 
   1096 True if the file is connected to a TTY device.
   1097 [clinic start generated code]*/
   1098 
   1099 static PyObject *
   1100 _io_FileIO_isatty_impl(fileio *self)
   1101 /*[clinic end generated code: output=932c39924e9a8070 input=cd94ca1f5e95e843]*/
   1102 {
   1103     long res;
   1104 
   1105     if (self->fd < 0)
   1106         return err_closed();
   1107     Py_BEGIN_ALLOW_THREADS
   1108     _Py_BEGIN_SUPPRESS_IPH
   1109     res = isatty(self->fd);
   1110     _Py_END_SUPPRESS_IPH
   1111     Py_END_ALLOW_THREADS
   1112     return PyBool_FromLong(res);
   1113 }
   1114 
   1115 static PyObject *
   1116 fileio_getstate(fileio *self)
   1117 {
   1118     PyErr_Format(PyExc_TypeError,
   1119                  "cannot serialize '%s' object", Py_TYPE(self)->tp_name);
   1120     return NULL;
   1121 }
   1122 
   1123 #include "clinic/fileio.c.h"
   1124 
   1125 static PyMethodDef fileio_methods[] = {
   1126     _IO_FILEIO_READ_METHODDEF
   1127     _IO_FILEIO_READALL_METHODDEF
   1128     _IO_FILEIO_READINTO_METHODDEF
   1129     _IO_FILEIO_WRITE_METHODDEF
   1130     _IO_FILEIO_SEEK_METHODDEF
   1131     _IO_FILEIO_TELL_METHODDEF
   1132     _IO_FILEIO_TRUNCATE_METHODDEF
   1133     _IO_FILEIO_CLOSE_METHODDEF
   1134     _IO_FILEIO_SEEKABLE_METHODDEF
   1135     _IO_FILEIO_READABLE_METHODDEF
   1136     _IO_FILEIO_WRITABLE_METHODDEF
   1137     _IO_FILEIO_FILENO_METHODDEF
   1138     _IO_FILEIO_ISATTY_METHODDEF
   1139     {"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL},
   1140     {"__getstate__", (PyCFunction)fileio_getstate, METH_NOARGS, NULL},
   1141     {NULL,           NULL}             /* sentinel */
   1142 };
   1143 
   1144 /* 'closed' and 'mode' are attributes for backwards compatibility reasons. */
   1145 
   1146 static PyObject *
   1147 get_closed(fileio *self, void *closure)
   1148 {
   1149     return PyBool_FromLong((long)(self->fd < 0));
   1150 }
   1151 
   1152 static PyObject *
   1153 get_closefd(fileio *self, void *closure)
   1154 {
   1155     return PyBool_FromLong((long)(self->closefd));
   1156 }
   1157 
   1158 static PyObject *
   1159 get_mode(fileio *self, void *closure)
   1160 {
   1161     return PyUnicode_FromString(mode_string(self));
   1162 }
   1163 
   1164 static PyGetSetDef fileio_getsetlist[] = {
   1165     {"closed", (getter)get_closed, NULL, "True if the file is closed"},
   1166     {"closefd", (getter)get_closefd, NULL,
   1167         "True if the file descriptor will be closed by close()."},
   1168     {"mode", (getter)get_mode, NULL, "String giving the file mode"},
   1169     {NULL},
   1170 };
   1171 
   1172 static PyMemberDef fileio_members[] = {
   1173     {"_blksize", T_UINT, offsetof(fileio, blksize), 0},
   1174     {"_finalizing", T_BOOL, offsetof(fileio, finalizing), 0},
   1175     {NULL}
   1176 };
   1177 
   1178 PyTypeObject PyFileIO_Type = {
   1179     PyVarObject_HEAD_INIT(NULL, 0)
   1180     "_io.FileIO",
   1181     sizeof(fileio),
   1182     0,
   1183     (destructor)fileio_dealloc,                 /* tp_dealloc */
   1184     0,                                          /* tp_print */
   1185     0,                                          /* tp_getattr */
   1186     0,                                          /* tp_setattr */
   1187     0,                                          /* tp_reserved */
   1188     (reprfunc)fileio_repr,                      /* tp_repr */
   1189     0,                                          /* tp_as_number */
   1190     0,                                          /* tp_as_sequence */
   1191     0,                                          /* tp_as_mapping */
   1192     0,                                          /* tp_hash */
   1193     0,                                          /* tp_call */
   1194     0,                                          /* tp_str */
   1195     PyObject_GenericGetAttr,                    /* tp_getattro */
   1196     0,                                          /* tp_setattro */
   1197     0,                                          /* tp_as_buffer */
   1198     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
   1199         | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,       /* tp_flags */
   1200     _io_FileIO___init____doc__,                 /* tp_doc */
   1201     (traverseproc)fileio_traverse,              /* tp_traverse */
   1202     (inquiry)fileio_clear,                      /* tp_clear */
   1203     0,                                          /* tp_richcompare */
   1204     offsetof(fileio, weakreflist),      /* tp_weaklistoffset */
   1205     0,                                          /* tp_iter */
   1206     0,                                          /* tp_iternext */
   1207     fileio_methods,                             /* tp_methods */
   1208     fileio_members,                             /* tp_members */
   1209     fileio_getsetlist,                          /* tp_getset */
   1210     0,                                          /* tp_base */
   1211     0,                                          /* tp_dict */
   1212     0,                                          /* tp_descr_get */
   1213     0,                                          /* tp_descr_set */
   1214     offsetof(fileio, dict),         /* tp_dictoffset */
   1215     _io_FileIO___init__,                        /* tp_init */
   1216     PyType_GenericAlloc,                        /* tp_alloc */
   1217     fileio_new,                                 /* tp_new */
   1218     PyObject_GC_Del,                            /* tp_free */
   1219     0,                                          /* tp_is_gc */
   1220     0,                                          /* tp_bases */
   1221     0,                                          /* tp_mro */
   1222     0,                                          /* tp_cache */
   1223     0,                                          /* tp_subclasses */
   1224     0,                                          /* tp_weaklist */
   1225     0,                                          /* tp_del */
   1226     0,                                          /* tp_version_tag */
   1227     0,                                          /* tp_finalize */
   1228 };
   1229