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