LCOV - code coverage report
Current view: top level - Modules/_io - fileio.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 411 445 92.4 %
Date: 2022-07-20 13:12:14 Functions: 30 30 100.0 %
Branches: 227 275 82.5 %

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

Generated by: LCOV version 1.14