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