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