LCOV - code coverage report
Current view: top level - Objects - fileobject.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 151 210 71.9 %
Date: 2022-07-07 18:19:46 Functions: 15 19 78.9 %

          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

Generated by: LCOV version 1.14