LCOV - code coverage report
Current view: | top level - Modules/_io - fileio.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 212 | 450 | 47.1 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 20 | 30 | 66.7 %
|  |  | Branches: | 97 | 279 | 34.8 %

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

Generated by: LCOV version 1.14