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 *
PyFile_FromFd(int fd,const char * name,const char * mode,int buffering,const char * encoding,const char * errors,const char * newline,int closefd)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 *
PyFile_GetLine(PyObject * f,int n)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
PyFile_WriteObject(PyObject * v,PyObject * f,int flags)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
PyFile_WriteString(const char * s,PyObject * f)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
PyObject_AsFileDescriptor(PyObject * o)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
_PyLong_FileDescriptor_Converter(PyObject * o,void * ptr)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 *
_Py_UniversalNewlineFgetsWithSize(char * buf,int n,FILE * stream,PyObject * fobj,size_t * size)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 *
Py_UniversalNewlineFgets(char * buf,int n,FILE * stream,PyObject * fobj)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 *
PyFile_NewStdPrinter(int fd)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 *
stdprinter_write(PyStdPrinter_Object * self,PyObject * args)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 *
stdprinter_fileno(PyStdPrinter_Object * self,PyObject * Py_UNUSED (ignored))363  stdprinter_fileno(PyStdPrinter_Object *self, PyObject *Py_UNUSED(ignored))
364  {
365      return PyLong_FromLong((long) self->fd);
366  }
367  
368  static PyObject *
stdprinter_repr(PyStdPrinter_Object * self)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 *
stdprinter_noop(PyStdPrinter_Object * self,PyObject * Py_UNUSED (ignored))376  stdprinter_noop(PyStdPrinter_Object *self, PyObject *Py_UNUSED(ignored))
377  {
378      Py_RETURN_NONE;
379  }
380  
381  static PyObject *
stdprinter_isatty(PyStdPrinter_Object * self,PyObject * Py_UNUSED (ignored))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 *
get_closed(PyStdPrinter_Object * self,void * closure)406  get_closed(PyStdPrinter_Object *self, void *closure)
407  {
408      Py_RETURN_FALSE;
409  }
410  
411  static PyObject *
get_mode(PyStdPrinter_Object * self,void * closure)412  get_mode(PyStdPrinter_Object *self, void *closure)
413  {
414      return PyUnicode_FromString("w");
415  }
416  
417  static PyObject *
get_encoding(PyStdPrinter_Object * self,void * closure)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
PyFile_SetOpenCodeHook(Py_OpenCodeHookFunction hook,void * userData)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 *
PyFile_OpenCodeObject(PyObject * path)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 *
PyFile_OpenCode(const char * utf8path)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
541