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