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