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