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 26extern "C" { 27#endif 28 29/* External C interface */ 30 31PyObject * 32PyFile_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 52PyObject * 53PyFile_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 116int 117PyFile_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 146int 147PyFile_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 176int 177PyObject_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 222int 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 233char * 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 276char * 277Py_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 287typedef struct { 288 PyObject_HEAD 289 int fd; 290} PyStdPrinter_Object; 291 292PyObject * 293PyFile_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 310static PyObject * 311stdprinter_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 362static PyObject * 363stdprinter_fileno(PyStdPrinter_Object *self, PyObject *Py_UNUSED(ignored)) 364{ 365 return PyLong_FromLong((long) self->fd); 366} 367 368static PyObject * 369stdprinter_repr(PyStdPrinter_Object *self) 370{ 371 return PyUnicode_FromFormat("<stdprinter(fd=%d) object at %p>", 372 self->fd, self); 373} 374 375static PyObject * 376stdprinter_noop(PyStdPrinter_Object *self, PyObject *Py_UNUSED(ignored)) 377{ 378 Py_RETURN_NONE; 379} 380 381static PyObject * 382stdprinter_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 396static 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 405static PyObject * 406get_closed(PyStdPrinter_Object *self, void *closure) 407{ 408 Py_RETURN_FALSE; 409} 410 411static PyObject * 412get_mode(PyStdPrinter_Object *self, void *closure) 413{ 414 return PyUnicode_FromString("w"); 415} 416 417static PyObject * 418get_encoding(PyStdPrinter_Object *self, void *closure) 419{ 420 Py_RETURN_NONE; 421} 422 423static 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 430PyTypeObject 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 479int 480PyFile_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 499PyObject * 500PyFile_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 524PyObject * 525PyFile_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