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