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