• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* File object implementation (what's left of it -- see io.py) */
2 
3 #include "Python.h"
4 #include "pycore_call.h"          // _PyObject_CallNoArgs()
5 #include "pycore_runtime.h"       // _PyRuntime
6 
7 #ifdef HAVE_UNISTD_H
8 #  include <unistd.h>             // isatty()
9 #endif
10 
11 #if defined(HAVE_GETC_UNLOCKED) && !defined(_Py_MEMORY_SANITIZER)
12    /* clang MemorySanitizer doesn't yet understand getc_unlocked. */
13 #  define GETC(f) getc_unlocked(f)
14 #  define FLOCKFILE(f) flockfile(f)
15 #  define FUNLOCKFILE(f) funlockfile(f)
16 #else
17 #  define GETC(f) getc(f)
18 #  define FLOCKFILE(f)
19 #  define FUNLOCKFILE(f)
20 #endif
21 
22 /* Newline flags */
23 #define NEWLINE_UNKNOWN 0       /* No newline seen, yet */
24 #define NEWLINE_CR 1            /* \r newline seen */
25 #define NEWLINE_LF 2            /* \n newline seen */
26 #define NEWLINE_CRLF 4          /* \r\n newline seen */
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 *open, *stream;
35 
36     /* import _io in case we are being used to open io.py */
37     open = _PyImport_GetModuleAttrString("_io", "open");
38     if (open == NULL)
39         return NULL;
40     stream = PyObject_CallFunction(open, "isisssO", fd, mode,
41                                   buffering, encoding, errors,
42                                   newline, closefd ? Py_True : Py_False);
43     Py_DECREF(open);
44     if (stream == NULL)
45         return NULL;
46     /* ignore name attribute because the name attribute of _BufferedIOMixin
47        and TextIOWrapper is read only */
48     return stream;
49 }
50 
51 PyObject *
PyFile_GetLine(PyObject * f,int n)52 PyFile_GetLine(PyObject *f, int n)
53 {
54     PyObject *result;
55 
56     if (f == NULL) {
57         PyErr_BadInternalCall();
58         return NULL;
59     }
60 
61     if (n <= 0) {
62         result = PyObject_CallMethodNoArgs(f, &_Py_ID(readline));
63     }
64     else {
65         result = _PyObject_CallMethod(f, &_Py_ID(readline), "i", n);
66     }
67     if (result != NULL && !PyBytes_Check(result) &&
68         !PyUnicode_Check(result)) {
69         Py_SETREF(result, NULL);
70         PyErr_SetString(PyExc_TypeError,
71                    "object.readline() returned non-string");
72     }
73 
74     if (n < 0 && result != NULL && PyBytes_Check(result)) {
75         const char *s = PyBytes_AS_STRING(result);
76         Py_ssize_t len = PyBytes_GET_SIZE(result);
77         if (len == 0) {
78             Py_SETREF(result, NULL);
79             PyErr_SetString(PyExc_EOFError,
80                             "EOF when reading a line");
81         }
82         else if (s[len-1] == '\n') {
83             (void) _PyBytes_Resize(&result, len-1);
84         }
85     }
86     if (n < 0 && result != NULL && PyUnicode_Check(result)) {
87         Py_ssize_t len = PyUnicode_GET_LENGTH(result);
88         if (len == 0) {
89             Py_SETREF(result, NULL);
90             PyErr_SetString(PyExc_EOFError,
91                             "EOF when reading a line");
92         }
93         else if (PyUnicode_READ_CHAR(result, len-1) == '\n') {
94             PyObject *v;
95             v = PyUnicode_Substring(result, 0, len-1);
96             Py_SETREF(result, v);
97         }
98     }
99     return result;
100 }
101 
102 /* Interfaces to write objects/strings to file-like objects */
103 
104 int
PyFile_WriteObject(PyObject * v,PyObject * f,int flags)105 PyFile_WriteObject(PyObject *v, PyObject *f, int flags)
106 {
107     PyObject *writer, *value, *result;
108 
109     if (f == NULL) {
110         PyErr_SetString(PyExc_TypeError, "writeobject with NULL file");
111         return -1;
112     }
113     writer = PyObject_GetAttr(f, &_Py_ID(write));
114     if (writer == NULL)
115         return -1;
116     if (flags & Py_PRINT_RAW) {
117         value = PyObject_Str(v);
118     }
119     else
120         value = PyObject_Repr(v);
121     if (value == NULL) {
122         Py_DECREF(writer);
123         return -1;
124     }
125     result = PyObject_CallOneArg(writer, value);
126     Py_DECREF(value);
127     Py_DECREF(writer);
128     if (result == NULL)
129         return -1;
130     Py_DECREF(result);
131     return 0;
132 }
133 
134 int
PyFile_WriteString(const char * s,PyObject * f)135 PyFile_WriteString(const char *s, PyObject *f)
136 {
137     if (f == NULL) {
138         /* Should be caused by a pre-existing error */
139         if (!PyErr_Occurred())
140             PyErr_SetString(PyExc_SystemError,
141                             "null file for PyFile_WriteString");
142         return -1;
143     }
144     else if (!PyErr_Occurred()) {
145         PyObject *v = PyUnicode_FromString(s);
146         int err;
147         if (v == NULL)
148             return -1;
149         err = PyFile_WriteObject(v, f, Py_PRINT_RAW);
150         Py_DECREF(v);
151         return err;
152     }
153     else
154         return -1;
155 }
156 
157 /* Try to get a file-descriptor from a Python object.  If the object
158    is an integer, its value is returned.  If not, the
159    object's fileno() method is called if it exists; the method must return
160    an integer, which is returned as the file descriptor value.
161    -1 is returned on failure.
162 */
163 
164 int
PyObject_AsFileDescriptor(PyObject * o)165 PyObject_AsFileDescriptor(PyObject *o)
166 {
167     int fd;
168     PyObject *meth;
169 
170     if (PyLong_Check(o)) {
171         if (PyBool_Check(o)) {
172             if (PyErr_WarnEx(PyExc_RuntimeWarning,
173                     "bool is used as a file descriptor", 1))
174             {
175                 return -1;
176             }
177         }
178         fd = PyLong_AsInt(o);
179     }
180     else if (PyObject_GetOptionalAttr(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
_PyLong_FileDescriptor_Converter(PyObject * o,void * ptr)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 *
_Py_UniversalNewlineFgetsWithSize(char * buf,int n,FILE * stream,PyObject * fobj,size_t * size)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 *
Py_UniversalNewlineFgets(char * buf,int n,FILE * stream,PyObject * fobj)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 *
PyFile_NewStdPrinter(int fd)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 *
stdprinter_write(PyStdPrinter_Object * self,PyObject * args)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 *
stdprinter_fileno(PyStdPrinter_Object * self,PyObject * Py_UNUSED (ignored))358 stdprinter_fileno(PyStdPrinter_Object *self, PyObject *Py_UNUSED(ignored))
359 {
360     return PyLong_FromLong((long) self->fd);
361 }
362 
363 static PyObject *
stdprinter_repr(PyStdPrinter_Object * self)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 *
stdprinter_noop(PyStdPrinter_Object * self,PyObject * Py_UNUSED (ignored))371 stdprinter_noop(PyStdPrinter_Object *self, PyObject *Py_UNUSED(ignored))
372 {
373     Py_RETURN_NONE;
374 }
375 
376 static PyObject *
stdprinter_isatty(PyStdPrinter_Object * self,PyObject * Py_UNUSED (ignored))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 *
get_closed(PyStdPrinter_Object * self,void * closure)401 get_closed(PyStdPrinter_Object *self, void *closure)
402 {
403     Py_RETURN_FALSE;
404 }
405 
406 static PyObject *
get_mode(PyStdPrinter_Object * self,void * closure)407 get_mode(PyStdPrinter_Object *self, void *closure)
408 {
409     return PyUnicode_FromString("w");
410 }
411 
412 static PyObject *
get_encoding(PyStdPrinter_Object * self,void * closure)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
PyFile_SetOpenCodeHook(Py_OpenCodeHookFunction hook,void * userData)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 *
PyFile_OpenCodeObject(PyObject * path)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 *
PyFile_OpenCode(const char * utf8path)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 int
_PyFile_Flush(PyObject * file)534 _PyFile_Flush(PyObject *file)
535 {
536     PyObject *tmp = PyObject_CallMethodNoArgs(file, &_Py_ID(flush));
537     if (tmp == NULL) {
538         return -1;
539     }
540     Py_DECREF(tmp);
541     return 0;
542 }
543