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