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