(root)/
Python-3.11.7/
Objects/
fileobject.c
       1  /* File object implementation (what's left of it -- see io.py) */
       2  
       3  #define PY_SSIZE_T_CLEAN
       4  #include "Python.h"
       5  #include "pycore_call.h"          // _PyObject_CallNoArgs()
       6  #include "pycore_runtime.h"       // _PyRuntime
       7  
       8  #if defined(HAVE_GETC_UNLOCKED) && !defined(_Py_MEMORY_SANITIZER)
       9  /* clang MemorySanitizer doesn't yet understand getc_unlocked. */
      10  #define GETC(f) getc_unlocked(f)
      11  #define FLOCKFILE(f) flockfile(f)
      12  #define FUNLOCKFILE(f) funlockfile(f)
      13  #else
      14  #define GETC(f) getc(f)
      15  #define FLOCKFILE(f)
      16  #define FUNLOCKFILE(f)
      17  #endif
      18  
      19  /* Newline flags */
      20  #define NEWLINE_UNKNOWN 0       /* No newline seen, yet */
      21  #define NEWLINE_CR 1            /* \r newline seen */
      22  #define NEWLINE_LF 2            /* \n newline seen */
      23  #define NEWLINE_CRLF 4          /* \r\n newline seen */
      24  
      25  #ifdef __cplusplus
      26  extern "C" {
      27  #endif
      28  
      29  /* External C interface */
      30  
      31  PyObject *
      32  PyFile_FromFd(int fd, const char *name, const char *mode, int buffering, const char *encoding,
      33                const char *errors, const char *newline, int closefd)
      34  {
      35      PyObject *io, *stream;
      36  
      37      /* import _io in case we are being used to open io.py */
      38      io = PyImport_ImportModule("_io");
      39      if (io == NULL)
      40          return NULL;
      41      stream = _PyObject_CallMethod(io, &_Py_ID(open), "isisssO", fd, mode,
      42                                    buffering, encoding, errors,
      43                                    newline, closefd ? Py_True : Py_False);
      44      Py_DECREF(io);
      45      if (stream == NULL)
      46          return NULL;
      47      /* ignore name attribute because the name attribute of _BufferedIOMixin
      48         and TextIOWrapper is read only */
      49      return stream;
      50  }
      51  
      52  PyObject *
      53  PyFile_GetLine(PyObject *f, int n)
      54  {
      55      PyObject *result;
      56  
      57      if (f == NULL) {
      58          PyErr_BadInternalCall();
      59          return NULL;
      60      }
      61  
      62      if (n <= 0) {
      63          result = PyObject_CallMethodNoArgs(f, &_Py_ID(readline));
      64      }
      65      else {
      66          result = _PyObject_CallMethod(f, &_Py_ID(readline), "i", n);
      67      }
      68      if (result != NULL && !PyBytes_Check(result) &&
      69          !PyUnicode_Check(result)) {
      70          Py_DECREF(result);
      71          result = NULL;
      72          PyErr_SetString(PyExc_TypeError,
      73                     "object.readline() returned non-string");
      74      }
      75  
      76      if (n < 0 && result != NULL && PyBytes_Check(result)) {
      77          const char *s = PyBytes_AS_STRING(result);
      78          Py_ssize_t len = PyBytes_GET_SIZE(result);
      79          if (len == 0) {
      80              Py_DECREF(result);
      81              result = NULL;
      82              PyErr_SetString(PyExc_EOFError,
      83                              "EOF when reading a line");
      84          }
      85          else if (s[len-1] == '\n') {
      86              if (Py_REFCNT(result) == 1)
      87                  _PyBytes_Resize(&result, len-1);
      88              else {
      89                  PyObject *v;
      90                  v = PyBytes_FromStringAndSize(s, len-1);
      91                  Py_DECREF(result);
      92                  result = v;
      93              }
      94          }
      95      }
      96      if (n < 0 && result != NULL && PyUnicode_Check(result)) {
      97          Py_ssize_t len = PyUnicode_GET_LENGTH(result);
      98          if (len == 0) {
      99              Py_DECREF(result);
     100              result = NULL;
     101              PyErr_SetString(PyExc_EOFError,
     102                              "EOF when reading a line");
     103          }
     104          else if (PyUnicode_READ_CHAR(result, len-1) == '\n') {
     105              PyObject *v;
     106              v = PyUnicode_Substring(result, 0, len-1);
     107              Py_DECREF(result);
     108              result = v;
     109          }
     110      }
     111      return result;
     112  }
     113  
     114  /* Interfaces to write objects/strings to file-like objects */
     115  
     116  int
     117  PyFile_WriteObject(PyObject *v, PyObject *f, int flags)
     118  {
     119      PyObject *writer, *value, *result;
     120  
     121      if (f == NULL) {
     122          PyErr_SetString(PyExc_TypeError, "writeobject with NULL file");
     123          return -1;
     124      }
     125      writer = PyObject_GetAttr(f, &_Py_ID(write));
     126      if (writer == NULL)
     127          return -1;
     128      if (flags & Py_PRINT_RAW) {
     129          value = PyObject_Str(v);
     130      }
     131      else
     132          value = PyObject_Repr(v);
     133      if (value == NULL) {
     134          Py_DECREF(writer);
     135          return -1;
     136      }
     137      result = PyObject_CallOneArg(writer, value);
     138      Py_DECREF(value);
     139      Py_DECREF(writer);
     140      if (result == NULL)
     141          return -1;
     142      Py_DECREF(result);
     143      return 0;
     144  }
     145  
     146  int
     147  PyFile_WriteString(const char *s, PyObject *f)
     148  {
     149      if (f == NULL) {
     150          /* Should be caused by a pre-existing error */
     151          if (!PyErr_Occurred())
     152              PyErr_SetString(PyExc_SystemError,
     153                              "null file for PyFile_WriteString");
     154          return -1;
     155      }
     156      else if (!PyErr_Occurred()) {
     157          PyObject *v = PyUnicode_FromString(s);
     158          int err;
     159          if (v == NULL)
     160              return -1;
     161          err = PyFile_WriteObject(v, f, Py_PRINT_RAW);
     162          Py_DECREF(v);
     163          return err;
     164      }
     165      else
     166          return -1;
     167  }
     168  
     169  /* Try to get a file-descriptor from a Python object.  If the object
     170     is an integer, its value is returned.  If not, the
     171     object's fileno() method is called if it exists; the method must return
     172     an integer, which is returned as the file descriptor value.
     173     -1 is returned on failure.
     174  */
     175  
     176  int
     177  PyObject_AsFileDescriptor(PyObject *o)
     178  {
     179      int fd;
     180      PyObject *meth;
     181  
     182      if (PyLong_Check(o)) {
     183          fd = _PyLong_AsInt(o);
     184      }
     185      else if (_PyObject_LookupAttr(o, &_Py_ID(fileno), &meth) < 0) {
     186          return -1;
     187      }
     188      else if (meth != NULL) {
     189          PyObject *fno = _PyObject_CallNoArgs(meth);
     190          Py_DECREF(meth);
     191          if (fno == NULL)
     192              return -1;
     193  
     194          if (PyLong_Check(fno)) {
     195              fd = _PyLong_AsInt(fno);
     196              Py_DECREF(fno);
     197          }
     198          else {
     199              PyErr_SetString(PyExc_TypeError,
     200                              "fileno() returned a non-integer");
     201              Py_DECREF(fno);
     202              return -1;
     203          }
     204      }
     205      else {
     206          PyErr_SetString(PyExc_TypeError,
     207                          "argument must be an int, or have a fileno() method.");
     208          return -1;
     209      }
     210  
     211      if (fd == -1 && PyErr_Occurred())
     212          return -1;
     213      if (fd < 0) {
     214          PyErr_Format(PyExc_ValueError,
     215                       "file descriptor cannot be a negative integer (%i)",
     216                       fd);
     217          return -1;
     218      }
     219      return fd;
     220  }
     221  
     222  int
     223  _PyLong_FileDescriptor_Converter(PyObject *o, void *ptr)
     224  {
     225      int fd = PyObject_AsFileDescriptor(o);
     226      if (fd == -1) {
     227          return 0;
     228      }
     229      *(int *)ptr = fd;
     230      return 1;
     231  }
     232  
     233  char *
     234  _Py_UniversalNewlineFgetsWithSize(char *buf, int n, FILE *stream, PyObject *fobj, size_t* size)
     235  {
     236      char *p = buf;
     237      int c;
     238  
     239      if (fobj) {
     240          errno = ENXIO;          /* What can you do... */
     241          return NULL;
     242      }
     243      FLOCKFILE(stream);
     244      while (--n > 0 && (c = GETC(stream)) != EOF ) {
     245          if (c == '\r') {
     246              // A \r is translated into a \n, and we skip an adjacent \n, if any.
     247              c = GETC(stream);
     248              if (c != '\n') {
     249                  ungetc(c, stream);
     250                  c = '\n';
     251              }
     252          }
     253          *p++ = c;
     254          if (c == '\n') {
     255              break;
     256          }
     257      }
     258      FUNLOCKFILE(stream);
     259      *p = '\0';
     260      if (p == buf) {
     261          return NULL;
     262      }
     263      *size = p - buf;
     264      return buf;
     265  }
     266  
     267  /*
     268  ** Py_UniversalNewlineFgets is an fgets variation that understands
     269  ** all of \r, \n and \r\n conventions.
     270  ** The stream should be opened in binary mode.
     271  ** The fobj parameter exists solely for legacy reasons and must be NULL.
     272  ** Note that we need no error handling: fgets() treats error and eof
     273  ** identically.
     274  */
     275  
     276  char *
     277  Py_UniversalNewlineFgets(char *buf, int n, FILE *stream, PyObject *fobj) {
     278      size_t size;
     279      return _Py_UniversalNewlineFgetsWithSize(buf, n, stream, fobj, &size);
     280  }
     281  
     282  /* **************************** std printer ****************************
     283   * The stdprinter is used during the boot strapping phase as a preliminary
     284   * file like object for sys.stderr.
     285   */
     286  
     287  typedef struct {
     288      PyObject_HEAD
     289      int fd;
     290  } PyStdPrinter_Object;
     291  
     292  PyObject *
     293  PyFile_NewStdPrinter(int fd)
     294  {
     295      PyStdPrinter_Object *self;
     296  
     297      if (fd != fileno(stdout) && fd != fileno(stderr)) {
     298          /* not enough infrastructure for PyErr_BadInternalCall() */
     299          return NULL;
     300      }
     301  
     302      self = PyObject_New(PyStdPrinter_Object,
     303                          &PyStdPrinter_Type);
     304      if (self != NULL) {
     305          self->fd = fd;
     306      }
     307      return (PyObject*)self;
     308  }
     309  
     310  static PyObject *
     311  stdprinter_write(PyStdPrinter_Object *self, PyObject *args)
     312  {
     313      PyObject *unicode;
     314      PyObject *bytes = NULL;
     315      const char *str;
     316      Py_ssize_t n;
     317      int err;
     318  
     319      /* The function can clear the current exception */
     320      assert(!PyErr_Occurred());
     321  
     322      if (self->fd < 0) {
     323          /* fd might be invalid on Windows
     324           * I can't raise an exception here. It may lead to an
     325           * unlimited recursion in the case stderr is invalid.
     326           */
     327          Py_RETURN_NONE;
     328      }
     329  
     330      if (!PyArg_ParseTuple(args, "U", &unicode)) {
     331          return NULL;
     332      }
     333  
     334      /* Encode Unicode to UTF-8/backslashreplace */
     335      str = PyUnicode_AsUTF8AndSize(unicode, &n);
     336      if (str == NULL) {
     337          PyErr_Clear();
     338          bytes = _PyUnicode_AsUTF8String(unicode, "backslashreplace");
     339          if (bytes == NULL)
     340              return NULL;
     341          str = PyBytes_AS_STRING(bytes);
     342          n = PyBytes_GET_SIZE(bytes);
     343      }
     344  
     345      n = _Py_write(self->fd, str, n);
     346      /* save errno, it can be modified indirectly by Py_XDECREF() */
     347      err = errno;
     348  
     349      Py_XDECREF(bytes);
     350  
     351      if (n == -1) {
     352          if (err == EAGAIN) {
     353              PyErr_Clear();
     354              Py_RETURN_NONE;
     355          }
     356          return NULL;
     357      }
     358  
     359      return PyLong_FromSsize_t(n);
     360  }
     361  
     362  static PyObject *
     363  stdprinter_fileno(PyStdPrinter_Object *self, PyObject *Py_UNUSED(ignored))
     364  {
     365      return PyLong_FromLong((long) self->fd);
     366  }
     367  
     368  static PyObject *
     369  stdprinter_repr(PyStdPrinter_Object *self)
     370  {
     371      return PyUnicode_FromFormat("<stdprinter(fd=%d) object at %p>",
     372                                  self->fd, self);
     373  }
     374  
     375  static PyObject *
     376  stdprinter_noop(PyStdPrinter_Object *self, PyObject *Py_UNUSED(ignored))
     377  {
     378      Py_RETURN_NONE;
     379  }
     380  
     381  static PyObject *
     382  stdprinter_isatty(PyStdPrinter_Object *self, PyObject *Py_UNUSED(ignored))
     383  {
     384      long res;
     385      if (self->fd < 0) {
     386          Py_RETURN_FALSE;
     387      }
     388  
     389      Py_BEGIN_ALLOW_THREADS
     390      res = isatty(self->fd);
     391      Py_END_ALLOW_THREADS
     392  
     393      return PyBool_FromLong(res);
     394  }
     395  
     396  static PyMethodDef stdprinter_methods[] = {
     397      {"close",           (PyCFunction)stdprinter_noop, METH_NOARGS, ""},
     398      {"flush",           (PyCFunction)stdprinter_noop, METH_NOARGS, ""},
     399      {"fileno",          (PyCFunction)stdprinter_fileno, METH_NOARGS, ""},
     400      {"isatty",          (PyCFunction)stdprinter_isatty, METH_NOARGS, ""},
     401      {"write",           (PyCFunction)stdprinter_write, METH_VARARGS, ""},
     402      {NULL,              NULL}  /*sentinel */
     403  };
     404  
     405  static PyObject *
     406  get_closed(PyStdPrinter_Object *self, void *closure)
     407  {
     408      Py_RETURN_FALSE;
     409  }
     410  
     411  static PyObject *
     412  get_mode(PyStdPrinter_Object *self, void *closure)
     413  {
     414      return PyUnicode_FromString("w");
     415  }
     416  
     417  static PyObject *
     418  get_encoding(PyStdPrinter_Object *self, void *closure)
     419  {
     420      Py_RETURN_NONE;
     421  }
     422  
     423  static PyGetSetDef stdprinter_getsetlist[] = {
     424      {"closed", (getter)get_closed, NULL, "True if the file is closed"},
     425      {"encoding", (getter)get_encoding, NULL, "Encoding of the file"},
     426      {"mode", (getter)get_mode, NULL, "String giving the file mode"},
     427      {0},
     428  };
     429  
     430  PyTypeObject PyStdPrinter_Type = {
     431      PyVarObject_HEAD_INIT(&PyType_Type, 0)
     432      "stderrprinter",                            /* tp_name */
     433      sizeof(PyStdPrinter_Object),                /* tp_basicsize */
     434      0,                                          /* tp_itemsize */
     435      /* methods */
     436      0,                                          /* tp_dealloc */
     437      0,                                          /* tp_vectorcall_offset */
     438      0,                                          /* tp_getattr */
     439      0,                                          /* tp_setattr */
     440      0,                                          /* tp_as_async */
     441      (reprfunc)stdprinter_repr,                  /* tp_repr */
     442      0,                                          /* tp_as_number */
     443      0,                                          /* tp_as_sequence */
     444      0,                                          /* tp_as_mapping */
     445      0,                                          /* tp_hash */
     446      0,                                          /* tp_call */
     447      0,                                          /* tp_str */
     448      PyObject_GenericGetAttr,                    /* tp_getattro */
     449      0,                                          /* tp_setattro */
     450      0,                                          /* tp_as_buffer */
     451      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, /* tp_flags */
     452      0,                                          /* tp_doc */
     453      0,                                          /* tp_traverse */
     454      0,                                          /* tp_clear */
     455      0,                                          /* tp_richcompare */
     456      0,                                          /* tp_weaklistoffset */
     457      0,                                          /* tp_iter */
     458      0,                                          /* tp_iternext */
     459      stdprinter_methods,                         /* tp_methods */
     460      0,                                          /* tp_members */
     461      stdprinter_getsetlist,                      /* tp_getset */
     462      0,                                          /* tp_base */
     463      0,                                          /* tp_dict */
     464      0,                                          /* tp_descr_get */
     465      0,                                          /* tp_descr_set */
     466      0,                                          /* tp_dictoffset */
     467      0,                                          /* tp_init */
     468      PyType_GenericAlloc,                        /* tp_alloc */
     469      0,                                          /* tp_new */
     470      PyObject_Del,                               /* tp_free */
     471  };
     472  
     473  
     474  /* ************************** open_code hook ***************************
     475   * The open_code hook allows embedders to override the method used to
     476   * open files that are going to be used by the runtime to execute code
     477   */
     478  
     479  int
     480  PyFile_SetOpenCodeHook(Py_OpenCodeHookFunction hook, void *userData) {
     481      if (Py_IsInitialized() &&
     482          PySys_Audit("setopencodehook", NULL) < 0) {
     483          return -1;
     484      }
     485  
     486      if (_PyRuntime.open_code_hook) {
     487          if (Py_IsInitialized()) {
     488              PyErr_SetString(PyExc_SystemError,
     489                  "failed to change existing open_code hook");
     490          }
     491          return -1;
     492      }
     493  
     494      _PyRuntime.open_code_hook = hook;
     495      _PyRuntime.open_code_userdata = userData;
     496      return 0;
     497  }
     498  
     499  PyObject *
     500  PyFile_OpenCodeObject(PyObject *path)
     501  {
     502      PyObject *iomod, *f = NULL;
     503  
     504      if (!PyUnicode_Check(path)) {
     505          PyErr_Format(PyExc_TypeError, "'path' must be 'str', not '%.200s'",
     506                       Py_TYPE(path)->tp_name);
     507          return NULL;
     508      }
     509  
     510      Py_OpenCodeHookFunction hook = _PyRuntime.open_code_hook;
     511      if (hook) {
     512          f = hook(path, _PyRuntime.open_code_userdata);
     513      } else {
     514          iomod = PyImport_ImportModule("_io");
     515          if (iomod) {
     516              f = _PyObject_CallMethod(iomod, &_Py_ID(open), "Os", path, "rb");
     517              Py_DECREF(iomod);
     518          }
     519      }
     520  
     521      return f;
     522  }
     523  
     524  PyObject *
     525  PyFile_OpenCode(const char *utf8path)
     526  {
     527      PyObject *pathobj = PyUnicode_FromString(utf8path);
     528      PyObject *f;
     529      if (!pathobj) {
     530          return NULL;
     531      }
     532      f = PyFile_OpenCodeObject(pathobj);
     533      Py_DECREF(pathobj);
     534      return f;
     535  }
     536  
     537  
     538  #ifdef __cplusplus
     539  }
     540  #endif