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