LCOV - code coverage report
Current view: top level - libreoffice/workdir/unxlngi6.pro/UnpackedTarball/python3/Modules/_io - bufferedio.c (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 164 1049 15.6 %
Date: 2012-12-17 Functions: 20 74 27.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :     An implementation of Buffered I/O as defined by PEP 3116 - "New I/O"
       3             : 
       4             :     Classes defined here: BufferedIOBase, BufferedReader, BufferedWriter,
       5             :     BufferedRandom.
       6             : 
       7             :     Written by Amaury Forgeot d'Arc and Antoine Pitrou
       8             : */
       9             : 
      10             : #define PY_SSIZE_T_CLEAN
      11             : #include "Python.h"
      12             : #include "structmember.h"
      13             : #include "pythread.h"
      14             : #include "_iomodule.h"
      15             : 
      16             : _Py_IDENTIFIER(close);
      17             : _Py_IDENTIFIER(_dealloc_warn);
      18             : _Py_IDENTIFIER(flush);
      19             : _Py_IDENTIFIER(isatty);
      20             : _Py_IDENTIFIER(mode);
      21             : _Py_IDENTIFIER(name);
      22             : _Py_IDENTIFIER(peek);
      23             : _Py_IDENTIFIER(read);
      24             : _Py_IDENTIFIER(read1);
      25             : _Py_IDENTIFIER(readable);
      26             : _Py_IDENTIFIER(readinto);
      27             : _Py_IDENTIFIER(writable);
      28             : _Py_IDENTIFIER(write);
      29             : 
      30             : /*
      31             :  * BufferedIOBase class, inherits from IOBase.
      32             :  */
      33             : PyDoc_STRVAR(bufferediobase_doc,
      34             :     "Base class for buffered IO objects.\n"
      35             :     "\n"
      36             :     "The main difference with RawIOBase is that the read() method\n"
      37             :     "supports omitting the size argument, and does not have a default\n"
      38             :     "implementation that defers to readinto().\n"
      39             :     "\n"
      40             :     "In addition, read(), readinto() and write() may raise\n"
      41             :     "BlockingIOError if the underlying raw stream is in non-blocking\n"
      42             :     "mode and not ready; unlike their raw counterparts, they will never\n"
      43             :     "return None.\n"
      44             :     "\n"
      45             :     "A typical implementation should not inherit from a RawIOBase\n"
      46             :     "implementation, but wrap one.\n"
      47             :     );
      48             : 
      49             : static PyObject *
      50           0 : bufferediobase_readinto(PyObject *self, PyObject *args)
      51             : {
      52             :     Py_buffer buf;
      53             :     Py_ssize_t len;
      54             :     PyObject *data;
      55             :     _Py_IDENTIFIER(read);
      56             : 
      57           0 :     if (!PyArg_ParseTuple(args, "w*:readinto", &buf)) {
      58           0 :         return NULL;
      59             :     }
      60             : 
      61           0 :     data = _PyObject_CallMethodId(self, &PyId_read, "n", buf.len);
      62           0 :     if (data == NULL)
      63           0 :         goto error;
      64             : 
      65           0 :     if (!PyBytes_Check(data)) {
      66           0 :         Py_DECREF(data);
      67           0 :         PyErr_SetString(PyExc_TypeError, "read() should return bytes");
      68           0 :         goto error;
      69             :     }
      70             : 
      71           0 :     len = Py_SIZE(data);
      72           0 :     memcpy(buf.buf, PyBytes_AS_STRING(data), len);
      73             : 
      74           0 :     PyBuffer_Release(&buf);
      75           0 :     Py_DECREF(data);
      76             : 
      77           0 :     return PyLong_FromSsize_t(len);
      78             : 
      79             :   error:
      80           0 :     PyBuffer_Release(&buf);
      81           0 :     return NULL;
      82             : }
      83             : 
      84             : static PyObject *
      85           0 : bufferediobase_unsupported(const char *message)
      86             : {
      87           0 :     PyErr_SetString(IO_STATE->unsupported_operation, message);
      88           0 :     return NULL;
      89             : }
      90             : 
      91             : PyDoc_STRVAR(bufferediobase_detach_doc,
      92             :     "Disconnect this buffer from its underlying raw stream and return it.\n"
      93             :     "\n"
      94             :     "After the raw stream has been detached, the buffer is in an unusable\n"
      95             :     "state.\n");
      96             : 
      97             : static PyObject *
      98           0 : bufferediobase_detach(PyObject *self)
      99             : {
     100           0 :     return bufferediobase_unsupported("detach");
     101             : }
     102             : 
     103             : PyDoc_STRVAR(bufferediobase_read_doc,
     104             :     "Read and return up to n bytes.\n"
     105             :     "\n"
     106             :     "If the argument is omitted, None, or negative, reads and\n"
     107             :     "returns all data until EOF.\n"
     108             :     "\n"
     109             :     "If the argument is positive, and the underlying raw stream is\n"
     110             :     "not 'interactive', multiple raw reads may be issued to satisfy\n"
     111             :     "the byte count (unless EOF is reached first).  But for\n"
     112             :     "interactive raw streams (as well as sockets and pipes), at most\n"
     113             :     "one raw read will be issued, and a short result does not imply\n"
     114             :     "that EOF is imminent.\n"
     115             :     "\n"
     116             :     "Returns an empty bytes object on EOF.\n"
     117             :     "\n"
     118             :     "Returns None if the underlying raw stream was open in non-blocking\n"
     119             :     "mode and no data is available at the moment.\n");
     120             : 
     121             : static PyObject *
     122           0 : bufferediobase_read(PyObject *self, PyObject *args)
     123             : {
     124           0 :     return bufferediobase_unsupported("read");
     125             : }
     126             : 
     127             : PyDoc_STRVAR(bufferediobase_read1_doc,
     128             :     "Read and return up to n bytes, with at most one read() call\n"
     129             :     "to the underlying raw stream. A short result does not imply\n"
     130             :     "that EOF is imminent.\n"
     131             :     "\n"
     132             :     "Returns an empty bytes object on EOF.\n");
     133             : 
     134             : static PyObject *
     135           0 : bufferediobase_read1(PyObject *self, PyObject *args)
     136             : {
     137           0 :     return bufferediobase_unsupported("read1");
     138             : }
     139             : 
     140             : PyDoc_STRVAR(bufferediobase_write_doc,
     141             :     "Write the given buffer to the IO stream.\n"
     142             :     "\n"
     143             :     "Returns the number of bytes written, which is never less than\n"
     144             :     "len(b).\n"
     145             :     "\n"
     146             :     "Raises BlockingIOError if the buffer is full and the\n"
     147             :     "underlying raw stream cannot accept more data at the moment.\n");
     148             : 
     149             : static PyObject *
     150           0 : bufferediobase_write(PyObject *self, PyObject *args)
     151             : {
     152           0 :     return bufferediobase_unsupported("write");
     153             : }
     154             : 
     155             : 
     156             : static PyMethodDef bufferediobase_methods[] = {
     157             :     {"detach", (PyCFunction)bufferediobase_detach, METH_NOARGS, bufferediobase_detach_doc},
     158             :     {"read", bufferediobase_read, METH_VARARGS, bufferediobase_read_doc},
     159             :     {"read1", bufferediobase_read1, METH_VARARGS, bufferediobase_read1_doc},
     160             :     {"readinto", bufferediobase_readinto, METH_VARARGS, NULL},
     161             :     {"write", bufferediobase_write, METH_VARARGS, bufferediobase_write_doc},
     162             :     {NULL, NULL}
     163             : };
     164             : 
     165             : PyTypeObject PyBufferedIOBase_Type = {
     166             :     PyVarObject_HEAD_INIT(NULL, 0)
     167             :     "_io._BufferedIOBase",      /*tp_name*/
     168             :     0,                          /*tp_basicsize*/
     169             :     0,                          /*tp_itemsize*/
     170             :     0,                          /*tp_dealloc*/
     171             :     0,                          /*tp_print*/
     172             :     0,                          /*tp_getattr*/
     173             :     0,                          /*tp_setattr*/
     174             :     0,                          /*tp_compare */
     175             :     0,                          /*tp_repr*/
     176             :     0,                          /*tp_as_number*/
     177             :     0,                          /*tp_as_sequence*/
     178             :     0,                          /*tp_as_mapping*/
     179             :     0,                          /*tp_hash */
     180             :     0,                          /*tp_call*/
     181             :     0,                          /*tp_str*/
     182             :     0,                          /*tp_getattro*/
     183             :     0,                          /*tp_setattro*/
     184             :     0,                          /*tp_as_buffer*/
     185             :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
     186             :     bufferediobase_doc,         /* tp_doc */
     187             :     0,                          /* tp_traverse */
     188             :     0,                          /* tp_clear */
     189             :     0,                          /* tp_richcompare */
     190             :     0,                          /* tp_weaklistoffset */
     191             :     0,                          /* tp_iter */
     192             :     0,                          /* tp_iternext */
     193             :     bufferediobase_methods,     /* tp_methods */
     194             :     0,                          /* tp_members */
     195             :     0,                          /* tp_getset */
     196             :     &PyIOBase_Type,             /* tp_base */
     197             :     0,                          /* tp_dict */
     198             :     0,                          /* tp_descr_get */
     199             :     0,                          /* tp_descr_set */
     200             :     0,                          /* tp_dictoffset */
     201             :     0,                          /* tp_init */
     202             :     0,                          /* tp_alloc */
     203             :     0,                          /* tp_new */
     204             : };
     205             : 
     206             : 
     207             : typedef struct {
     208             :     PyObject_HEAD
     209             : 
     210             :     PyObject *raw;
     211             :     int ok;    /* Initialized? */
     212             :     int detached;
     213             :     int readable;
     214             :     int writable;
     215             :     int deallocating;
     216             : 
     217             :     /* True if this is a vanilla Buffered object (rather than a user derived
     218             :        class) *and* the raw stream is a vanilla FileIO object. */
     219             :     int fast_closed_checks;
     220             : 
     221             :     /* Absolute position inside the raw stream (-1 if unknown). */
     222             :     Py_off_t abs_pos;
     223             : 
     224             :     /* A static buffer of size `buffer_size` */
     225             :     char *buffer;
     226             :     /* Current logical position in the buffer. */
     227             :     Py_off_t pos;
     228             :     /* Position of the raw stream in the buffer. */
     229             :     Py_off_t raw_pos;
     230             : 
     231             :     /* Just after the last buffered byte in the buffer, or -1 if the buffer
     232             :        isn't ready for reading. */
     233             :     Py_off_t read_end;
     234             : 
     235             :     /* Just after the last byte actually written */
     236             :     Py_off_t write_pos;
     237             :     /* Just after the last byte waiting to be written, or -1 if the buffer
     238             :        isn't ready for writing. */
     239             :     Py_off_t write_end;
     240             : 
     241             : #ifdef WITH_THREAD
     242             :     PyThread_type_lock lock;
     243             :     volatile long owner;
     244             : #endif
     245             : 
     246             :     Py_ssize_t buffer_size;
     247             :     Py_ssize_t buffer_mask;
     248             : 
     249             :     PyObject *dict;
     250             :     PyObject *weakreflist;
     251             : } buffered;
     252             : 
     253             : /*
     254             :     Implementation notes:
     255             : 
     256             :     * BufferedReader, BufferedWriter and BufferedRandom try to share most
     257             :       methods (this is helped by the members `readable` and `writable`, which
     258             :       are initialized in the respective constructors)
     259             :     * They also share a single buffer for reading and writing. This enables
     260             :       interleaved reads and writes without flushing. It also makes the logic
     261             :       a bit trickier to get right.
     262             :     * The absolute position of the raw stream is cached, if possible, in the
     263             :       `abs_pos` member. It must be updated every time an operation is done
     264             :       on the raw stream. If not sure, it can be reinitialized by calling
     265             :       _buffered_raw_tell(), which queries the raw stream (_buffered_raw_seek()
     266             :       also does it). To read it, use RAW_TELL().
     267             :     * Three helpers, _bufferedreader_raw_read, _bufferedwriter_raw_write and
     268             :       _bufferedwriter_flush_unlocked do a lot of useful housekeeping.
     269             : 
     270             :     NOTE: we should try to maintain block alignment of reads and writes to the
     271             :     raw stream (according to the buffer size), but for now it is only done
     272             :     in read() and friends.
     273             : 
     274             : */
     275             : 
     276             : /* These macros protect the buffered object against concurrent operations. */
     277             : 
     278             : #ifdef WITH_THREAD
     279             : 
     280             : static int
     281           0 : _enter_buffered_busy(buffered *self)
     282             : {
     283           0 :     if (self->owner == PyThread_get_thread_ident()) {
     284           0 :         PyErr_Format(PyExc_RuntimeError,
     285             :                      "reentrant call inside %R", self);
     286           0 :         return 0;
     287             :     }
     288           0 :     Py_BEGIN_ALLOW_THREADS
     289           0 :     PyThread_acquire_lock(self->lock, 1);
     290           0 :     Py_END_ALLOW_THREADS
     291           0 :     return 1;
     292             : }
     293             : 
     294             : #define ENTER_BUFFERED(self) \
     295             :     ( (PyThread_acquire_lock(self->lock, 0) ? \
     296             :        1 : _enter_buffered_busy(self)) \
     297             :      && (self->owner = PyThread_get_thread_ident(), 1) )
     298             : 
     299             : #define LEAVE_BUFFERED(self) \
     300             :     do { \
     301             :         self->owner = 0; \
     302             :         PyThread_release_lock(self->lock); \
     303             :     } while(0);
     304             : 
     305             : #else
     306             : #define ENTER_BUFFERED(self) 1
     307             : #define LEAVE_BUFFERED(self)
     308             : #endif
     309             : 
     310             : #define CHECK_INITIALIZED(self) \
     311             :     if (self->ok <= 0) { \
     312             :         if (self->detached) { \
     313             :             PyErr_SetString(PyExc_ValueError, \
     314             :                  "raw stream has been detached"); \
     315             :         } else { \
     316             :             PyErr_SetString(PyExc_ValueError, \
     317             :                 "I/O operation on uninitialized object"); \
     318             :         } \
     319             :         return NULL; \
     320             :     }
     321             : 
     322             : #define CHECK_INITIALIZED_INT(self) \
     323             :     if (self->ok <= 0) { \
     324             :         if (self->detached) { \
     325             :             PyErr_SetString(PyExc_ValueError, \
     326             :                  "raw stream has been detached"); \
     327             :         } else { \
     328             :             PyErr_SetString(PyExc_ValueError, \
     329             :                 "I/O operation on uninitialized object"); \
     330             :         } \
     331             :         return -1; \
     332             :     }
     333             : 
     334             : #define IS_CLOSED(self) \
     335             :     (self->fast_closed_checks \
     336             :      ? _PyFileIO_closed(self->raw) \
     337             :      : buffered_closed(self))
     338             : 
     339             : #define CHECK_CLOSED(self, error_msg) \
     340             :     if (IS_CLOSED(self)) { \
     341             :         PyErr_SetString(PyExc_ValueError, error_msg); \
     342             :         return NULL; \
     343             :     }
     344             : 
     345             : 
     346             : #define VALID_READ_BUFFER(self) \
     347             :     (self->readable && self->read_end != -1)
     348             : 
     349             : #define VALID_WRITE_BUFFER(self) \
     350             :     (self->writable && self->write_end != -1)
     351             : 
     352             : #define ADJUST_POSITION(self, _new_pos) \
     353             :     do { \
     354             :         self->pos = _new_pos; \
     355             :         if (VALID_READ_BUFFER(self) && self->read_end < self->pos) \
     356             :             self->read_end = self->pos; \
     357             :     } while(0)
     358             : 
     359             : #define READAHEAD(self) \
     360             :     ((self->readable && VALID_READ_BUFFER(self)) \
     361             :         ? (self->read_end - self->pos) : 0)
     362             : 
     363             : #define RAW_OFFSET(self) \
     364             :     (((VALID_READ_BUFFER(self) || VALID_WRITE_BUFFER(self)) \
     365             :         && self->raw_pos >= 0) ? self->raw_pos - self->pos : 0)
     366             : 
     367             : #define RAW_TELL(self) \
     368             :     (self->abs_pos != -1 ? self->abs_pos : _buffered_raw_tell(self))
     369             : 
     370             : #define MINUS_LAST_BLOCK(self, size) \
     371             :     (self->buffer_mask ? \
     372             :         (size & ~self->buffer_mask) : \
     373             :         (self->buffer_size * (size / self->buffer_size)))
     374             : 
     375             : 
     376             : static void
     377           1 : buffered_dealloc(buffered *self)
     378             : {
     379           1 :     self->deallocating = 1;
     380           1 :     if (self->ok && _PyIOBase_finalize((PyObject *) self) < 0)
     381           1 :         return;
     382           1 :     _PyObject_GC_UNTRACK(self);
     383           1 :     self->ok = 0;
     384           1 :     if (self->weakreflist != NULL)
     385           0 :         PyObject_ClearWeakRefs((PyObject *)self);
     386           1 :     Py_CLEAR(self->raw);
     387           1 :     if (self->buffer) {
     388           1 :         PyMem_Free(self->buffer);
     389           1 :         self->buffer = NULL;
     390             :     }
     391             : #ifdef WITH_THREAD
     392           1 :     if (self->lock) {
     393           1 :         PyThread_free_lock(self->lock);
     394           1 :         self->lock = NULL;
     395             :     }
     396             : #endif
     397           1 :     Py_CLEAR(self->dict);
     398           1 :     Py_TYPE(self)->tp_free((PyObject *)self);
     399             : }
     400             : 
     401             : static PyObject *
     402           0 : buffered_sizeof(buffered *self, void *unused)
     403             : {
     404             :     Py_ssize_t res;
     405             : 
     406           0 :     res = sizeof(buffered);
     407           0 :     if (self->buffer)
     408           0 :         res += self->buffer_size;
     409           0 :     return PyLong_FromSsize_t(res);
     410             : }
     411             : 
     412             : static int
     413          10 : buffered_traverse(buffered *self, visitproc visit, void *arg)
     414             : {
     415          10 :     Py_VISIT(self->raw);
     416          10 :     Py_VISIT(self->dict);
     417          10 :     return 0;
     418             : }
     419             : 
     420             : static int
     421           0 : buffered_clear(buffered *self)
     422             : {
     423           0 :     if (self->ok && _PyIOBase_finalize((PyObject *) self) < 0)
     424           0 :         return -1;
     425           0 :     self->ok = 0;
     426           0 :     Py_CLEAR(self->raw);
     427           0 :     Py_CLEAR(self->dict);
     428           0 :     return 0;
     429             : }
     430             : 
     431             : /* Because this can call arbitrary code, it shouldn't be called when
     432             :    the refcount is 0 (that is, not directly from tp_dealloc unless
     433             :    the refcount has been temporarily re-incremented). */
     434             : static PyObject *
     435           1 : buffered_dealloc_warn(buffered *self, PyObject *source)
     436             : {
     437           1 :     if (self->ok && self->raw) {
     438             :         PyObject *r;
     439           1 :         r = _PyObject_CallMethodId(self->raw, &PyId__dealloc_warn, "O", source);
     440           1 :         if (r)
     441           1 :             Py_DECREF(r);
     442             :         else
     443           0 :             PyErr_Clear();
     444             :     }
     445           1 :     Py_RETURN_NONE;
     446             : }
     447             : 
     448             : /*
     449             :  * _BufferedIOMixin methods
     450             :  * This is not a class, just a collection of methods that will be reused
     451             :  * by BufferedReader and BufferedWriter
     452             :  */
     453             : 
     454             : /* Flush and close */
     455             : 
     456             : static PyObject *
     457           2 : buffered_simple_flush(buffered *self, PyObject *args)
     458             : {
     459           2 :     CHECK_INITIALIZED(self)
     460           2 :     return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_flush, NULL);
     461             : }
     462             : 
     463             : static int
     464           1 : buffered_closed(buffered *self)
     465             : {
     466             :     int closed;
     467             :     PyObject *res;
     468           1 :     CHECK_INITIALIZED_INT(self)
     469           1 :     res = PyObject_GetAttr(self->raw, _PyIO_str_closed);
     470           1 :     if (res == NULL)
     471           0 :         return -1;
     472           1 :     closed = PyObject_IsTrue(res);
     473           1 :     Py_DECREF(res);
     474           1 :     return closed;
     475             : }
     476             : 
     477             : static PyObject *
     478           3 : buffered_closed_get(buffered *self, void *context)
     479             : {
     480           3 :     CHECK_INITIALIZED(self)
     481           3 :     return PyObject_GetAttr(self->raw, _PyIO_str_closed);
     482             : }
     483             : 
     484             : static PyObject *
     485           1 : buffered_close(buffered *self, PyObject *args)
     486             : {
     487           1 :     PyObject *res = NULL;
     488             :     int r;
     489             : 
     490           1 :     CHECK_INITIALIZED(self)
     491           1 :     if (!ENTER_BUFFERED(self))
     492           0 :         return NULL;
     493             : 
     494           1 :     r = buffered_closed(self);
     495           1 :     if (r < 0)
     496           0 :         goto end;
     497           1 :     if (r > 0) {
     498           0 :         res = Py_None;
     499           0 :         Py_INCREF(res);
     500           0 :         goto end;
     501             :     }
     502             : 
     503           1 :     if (self->deallocating) {
     504           0 :         PyObject *r = buffered_dealloc_warn(self, (PyObject *) self);
     505           0 :         if (r)
     506           0 :             Py_DECREF(r);
     507             :         else
     508           0 :             PyErr_Clear();
     509             :     }
     510             :     /* flush() will most probably re-take the lock, so drop it first */
     511           1 :     LEAVE_BUFFERED(self)
     512           1 :     res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL);
     513           1 :     if (!ENTER_BUFFERED(self))
     514           0 :         return NULL;
     515           1 :     if (res == NULL) {
     516           0 :         goto end;
     517             :     }
     518           1 :     Py_XDECREF(res);
     519             : 
     520           1 :     res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_close, NULL);
     521             : 
     522             : end:
     523           1 :     LEAVE_BUFFERED(self)
     524           1 :     return res;
     525             : }
     526             : 
     527             : /* detach */
     528             : 
     529             : static PyObject *
     530           0 : buffered_detach(buffered *self, PyObject *args)
     531             : {
     532             :     PyObject *raw, *res;
     533           0 :     CHECK_INITIALIZED(self)
     534           0 :     res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL);
     535           0 :     if (res == NULL)
     536           0 :         return NULL;
     537           0 :     Py_DECREF(res);
     538           0 :     raw = self->raw;
     539           0 :     self->raw = NULL;
     540           0 :     self->detached = 1;
     541           0 :     self->ok = 0;
     542           0 :     return raw;
     543             : }
     544             : 
     545             : /* Inquiries */
     546             : 
     547             : static PyObject *
     548           4 : buffered_seekable(buffered *self, PyObject *args)
     549             : {
     550           4 :     CHECK_INITIALIZED(self)
     551           4 :     return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_seekable, NULL);
     552             : }
     553             : 
     554             : static PyObject *
     555           4 : buffered_readable(buffered *self, PyObject *args)
     556             : {
     557           4 :     CHECK_INITIALIZED(self)
     558           4 :     return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readable, NULL);
     559             : }
     560             : 
     561             : static PyObject *
     562           4 : buffered_writable(buffered *self, PyObject *args)
     563             : {
     564           4 :     CHECK_INITIALIZED(self)
     565           4 :     return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_writable, NULL);
     566             : }
     567             : 
     568             : static PyObject *
     569           1 : buffered_name_get(buffered *self, void *context)
     570             : {
     571           1 :     CHECK_INITIALIZED(self)
     572           1 :     return _PyObject_GetAttrId(self->raw, &PyId_name);
     573             : }
     574             : 
     575             : static PyObject *
     576           0 : buffered_mode_get(buffered *self, void *context)
     577             : {
     578           0 :     CHECK_INITIALIZED(self)
     579           0 :     return _PyObject_GetAttrId(self->raw, &PyId_mode);
     580             : }
     581             : 
     582             : /* Lower-level APIs */
     583             : 
     584             : static PyObject *
     585           4 : buffered_fileno(buffered *self, PyObject *args)
     586             : {
     587           4 :     CHECK_INITIALIZED(self)
     588           4 :     return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_fileno, NULL);
     589             : }
     590             : 
     591             : static PyObject *
     592           0 : buffered_isatty(buffered *self, PyObject *args)
     593             : {
     594           0 :     CHECK_INITIALIZED(self)
     595           0 :     return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_isatty, NULL);
     596             : }
     597             : 
     598             : /* Serialization */
     599             : 
     600             : static PyObject *
     601           0 : buffered_getstate(buffered *self, PyObject *args)
     602             : {
     603           0 :     PyErr_Format(PyExc_TypeError,
     604           0 :                  "cannot serialize '%s' object", Py_TYPE(self)->tp_name);
     605           0 :     return NULL;
     606             : }
     607             : 
     608             : /* Forward decls */
     609             : static PyObject *
     610             : _bufferedwriter_flush_unlocked(buffered *);
     611             : static Py_ssize_t
     612             : _bufferedreader_fill_buffer(buffered *self);
     613             : static void
     614             : _bufferedreader_reset_buf(buffered *self);
     615             : static void
     616             : _bufferedwriter_reset_buf(buffered *self);
     617             : static PyObject *
     618             : _bufferedreader_peek_unlocked(buffered *self);
     619             : static PyObject *
     620             : _bufferedreader_read_all(buffered *self);
     621             : static PyObject *
     622             : _bufferedreader_read_fast(buffered *self, Py_ssize_t);
     623             : static PyObject *
     624             : _bufferedreader_read_generic(buffered *self, Py_ssize_t);
     625             : static Py_ssize_t
     626             : _bufferedreader_raw_read(buffered *self, char *start, Py_ssize_t len);
     627             : 
     628             : /*
     629             :  * Helpers
     630             :  */
     631             : 
     632             : /* Sets the current error to BlockingIOError */
     633             : static void
     634           0 : _set_BlockingIOError(char *msg, Py_ssize_t written)
     635             : {
     636             :     PyObject *err;
     637           0 :     err = PyObject_CallFunction(PyExc_BlockingIOError, "isn",
     638           0 :                                 errno, msg, written);
     639           0 :     if (err)
     640           0 :         PyErr_SetObject(PyExc_BlockingIOError, err);
     641           0 :     Py_XDECREF(err);
     642           0 : }
     643             : 
     644             : /* Returns the address of the `written` member if a BlockingIOError was
     645             :    raised, NULL otherwise. The error is always re-raised. */
     646             : static Py_ssize_t *
     647           0 : _buffered_check_blocking_error(void)
     648             : {
     649             :     PyObject *t, *v, *tb;
     650             :     PyOSErrorObject *err;
     651             : 
     652           0 :     PyErr_Fetch(&t, &v, &tb);
     653           0 :     if (v == NULL || !PyErr_GivenExceptionMatches(v, PyExc_BlockingIOError)) {
     654           0 :         PyErr_Restore(t, v, tb);
     655           0 :         return NULL;
     656             :     }
     657           0 :     err = (PyOSErrorObject *) v;
     658             :     /* TODO: sanity check (err->written >= 0) */
     659           0 :     PyErr_Restore(t, v, tb);
     660           0 :     return &err->written;
     661             : }
     662             : 
     663             : static Py_off_t
     664           4 : _buffered_raw_tell(buffered *self)
     665             : {
     666             :     Py_off_t n;
     667             :     PyObject *res;
     668           4 :     res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_tell, NULL);
     669           4 :     if (res == NULL)
     670           3 :         return -1;
     671           1 :     n = PyNumber_AsOff_t(res, PyExc_ValueError);
     672           1 :     Py_DECREF(res);
     673           1 :     if (n < 0) {
     674           0 :         if (!PyErr_Occurred())
     675           0 :             PyErr_Format(PyExc_IOError,
     676             :                          "Raw stream returned invalid position %" PY_PRIdOFF,
     677             :                          (PY_OFF_T_COMPAT)n);
     678           0 :         return -1;
     679             :     }
     680           1 :     self->abs_pos = n;
     681           1 :     return n;
     682             : }
     683             : 
     684             : static Py_off_t
     685           0 : _buffered_raw_seek(buffered *self, Py_off_t target, int whence)
     686             : {
     687             :     PyObject *res, *posobj, *whenceobj;
     688             :     Py_off_t n;
     689             : 
     690           0 :     posobj = PyLong_FromOff_t(target);
     691           0 :     if (posobj == NULL)
     692           0 :         return -1;
     693           0 :     whenceobj = PyLong_FromLong(whence);
     694           0 :     if (whenceobj == NULL) {
     695           0 :         Py_DECREF(posobj);
     696           0 :         return -1;
     697             :     }
     698           0 :     res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_seek,
     699             :                                      posobj, whenceobj, NULL);
     700           0 :     Py_DECREF(posobj);
     701           0 :     Py_DECREF(whenceobj);
     702           0 :     if (res == NULL)
     703           0 :         return -1;
     704           0 :     n = PyNumber_AsOff_t(res, PyExc_ValueError);
     705           0 :     Py_DECREF(res);
     706           0 :     if (n < 0) {
     707           0 :         if (!PyErr_Occurred())
     708           0 :             PyErr_Format(PyExc_IOError,
     709             :                          "Raw stream returned invalid position %" PY_PRIdOFF,
     710             :                          (PY_OFF_T_COMPAT)n);
     711           0 :         return -1;
     712             :     }
     713           0 :     self->abs_pos = n;
     714           0 :     return n;
     715             : }
     716             : 
     717             : static int
     718           4 : _buffered_init(buffered *self)
     719             : {
     720             :     Py_ssize_t n;
     721           4 :     if (self->buffer_size <= 0) {
     722           0 :         PyErr_SetString(PyExc_ValueError,
     723             :             "buffer size must be strictly positive");
     724           0 :         return -1;
     725             :     }
     726           4 :     if (self->buffer)
     727           0 :         PyMem_Free(self->buffer);
     728           4 :     self->buffer = PyMem_Malloc(self->buffer_size);
     729           4 :     if (self->buffer == NULL) {
     730           0 :         PyErr_NoMemory();
     731           0 :         return -1;
     732             :     }
     733             : #ifdef WITH_THREAD
     734           4 :     if (self->lock)
     735           0 :         PyThread_free_lock(self->lock);
     736           4 :     self->lock = PyThread_allocate_lock();
     737           4 :     if (self->lock == NULL) {
     738           0 :         PyErr_SetString(PyExc_RuntimeError, "can't allocate read lock");
     739           0 :         return -1;
     740             :     }
     741           4 :     self->owner = 0;
     742             : #endif
     743             :     /* Find out whether buffer_size is a power of 2 */
     744             :     /* XXX is this optimization useful? */
     745           4 :     for (n = self->buffer_size - 1; n & 1; n >>= 1)
     746             :         ;
     747           4 :     if (n == 0)
     748           4 :         self->buffer_mask = self->buffer_size - 1;
     749             :     else
     750           0 :         self->buffer_mask = 0;
     751           4 :     if (_buffered_raw_tell(self) == -1)
     752           3 :         PyErr_Clear();
     753           4 :     return 0;
     754             : }
     755             : 
     756             : /* Return 1 if an EnvironmentError with errno == EINTR is set (and then
     757             :    clears the error indicator), 0 otherwise.
     758             :    Should only be called when PyErr_Occurred() is true.
     759             : */
     760             : int
     761           0 : _PyIO_trap_eintr(void)
     762             : {
     763             :     static PyObject *eintr_int = NULL;
     764             :     PyObject *typ, *val, *tb;
     765             :     PyEnvironmentErrorObject *env_err;
     766             : 
     767           0 :     if (eintr_int == NULL) {
     768           0 :         eintr_int = PyLong_FromLong(EINTR);
     769             :         assert(eintr_int != NULL);
     770             :     }
     771           0 :     if (!PyErr_ExceptionMatches(PyExc_EnvironmentError))
     772           0 :         return 0;
     773           0 :     PyErr_Fetch(&typ, &val, &tb);
     774           0 :     PyErr_NormalizeException(&typ, &val, &tb);
     775           0 :     env_err = (PyEnvironmentErrorObject *) val;
     776             :     assert(env_err != NULL);
     777           0 :     if (env_err->myerrno != NULL &&
     778           0 :         PyObject_RichCompareBool(env_err->myerrno, eintr_int, Py_EQ) > 0) {
     779           0 :         Py_DECREF(typ);
     780           0 :         Py_DECREF(val);
     781           0 :         Py_XDECREF(tb);
     782           0 :         return 1;
     783             :     }
     784             :     /* This silences any error set by PyObject_RichCompareBool() */
     785           0 :     PyErr_Restore(typ, val, tb);
     786           0 :     return 0;
     787             : }
     788             : 
     789             : /*
     790             :  * Shared methods and wrappers
     791             :  */
     792             : 
     793             : static PyObject *
     794           0 : buffered_flush_and_rewind_unlocked(buffered *self)
     795             : {
     796             :     PyObject *res;
     797             : 
     798           0 :     res = _bufferedwriter_flush_unlocked(self);
     799           0 :     if (res == NULL)
     800           0 :         return NULL;
     801           0 :     Py_DECREF(res);
     802             : 
     803           0 :     if (self->readable) {
     804             :         /* Rewind the raw stream so that its position corresponds to
     805             :            the current logical position. */
     806             :         Py_off_t n;
     807           0 :         n = _buffered_raw_seek(self, -RAW_OFFSET(self), 1);
     808           0 :         _bufferedreader_reset_buf(self);
     809           0 :         if (n == -1)
     810           0 :             return NULL;
     811             :     }
     812           0 :     Py_RETURN_NONE;
     813             : }
     814             : 
     815             : static PyObject *
     816           0 : buffered_flush(buffered *self, PyObject *args)
     817             : {
     818             :     PyObject *res;
     819             : 
     820           0 :     CHECK_INITIALIZED(self)
     821           0 :     CHECK_CLOSED(self, "flush of closed file")
     822             : 
     823           0 :     if (!ENTER_BUFFERED(self))
     824           0 :         return NULL;
     825           0 :     res = buffered_flush_and_rewind_unlocked(self);
     826           0 :     LEAVE_BUFFERED(self)
     827             : 
     828           0 :     return res;
     829             : }
     830             : 
     831             : static PyObject *
     832           0 : buffered_peek(buffered *self, PyObject *args)
     833             : {
     834           0 :     Py_ssize_t n = 0;
     835           0 :     PyObject *res = NULL;
     836             : 
     837           0 :     CHECK_INITIALIZED(self)
     838           0 :     if (!PyArg_ParseTuple(args, "|n:peek", &n)) {
     839           0 :         return NULL;
     840             :     }
     841             : 
     842           0 :     if (!ENTER_BUFFERED(self))
     843           0 :         return NULL;
     844             : 
     845           0 :     if (self->writable) {
     846           0 :         res = buffered_flush_and_rewind_unlocked(self);
     847           0 :         if (res == NULL)
     848           0 :             goto end;
     849           0 :         Py_CLEAR(res);
     850             :     }
     851           0 :     res = _bufferedreader_peek_unlocked(self);
     852             : 
     853             : end:
     854           0 :     LEAVE_BUFFERED(self)
     855           0 :     return res;
     856             : }
     857             : 
     858             : static PyObject *
     859           1 : buffered_read(buffered *self, PyObject *args)
     860             : {
     861           1 :     Py_ssize_t n = -1;
     862             :     PyObject *res;
     863             : 
     864           1 :     CHECK_INITIALIZED(self)
     865           1 :     if (!PyArg_ParseTuple(args, "|O&:read", &_PyIO_ConvertSsize_t, &n)) {
     866           0 :         return NULL;
     867             :     }
     868           1 :     if (n < -1) {
     869           0 :         PyErr_SetString(PyExc_ValueError,
     870             :                         "read length must be positive or -1");
     871           0 :         return NULL;
     872             :     }
     873             : 
     874           1 :     CHECK_CLOSED(self, "read of closed file")
     875             : 
     876           1 :     if (n == -1) {
     877             :         /* The number of bytes is unspecified, read until the end of stream */
     878           1 :         if (!ENTER_BUFFERED(self))
     879           0 :             return NULL;
     880           1 :         res = _bufferedreader_read_all(self);
     881             :     }
     882             :     else {
     883           0 :         res = _bufferedreader_read_fast(self, n);
     884           0 :         if (res != Py_None)
     885           0 :             return res;
     886           0 :         Py_DECREF(res);
     887           0 :         if (!ENTER_BUFFERED(self))
     888           0 :             return NULL;
     889           0 :         res = _bufferedreader_read_generic(self, n);
     890             :     }
     891             : 
     892           1 :     LEAVE_BUFFERED(self)
     893           1 :     return res;
     894             : }
     895             : 
     896             : static PyObject *
     897           0 : buffered_read1(buffered *self, PyObject *args)
     898             : {
     899             :     Py_ssize_t n, have, r;
     900           0 :     PyObject *res = NULL;
     901             : 
     902           0 :     CHECK_INITIALIZED(self)
     903           0 :     if (!PyArg_ParseTuple(args, "n:read1", &n)) {
     904           0 :         return NULL;
     905             :     }
     906             : 
     907           0 :     if (n < 0) {
     908           0 :         PyErr_SetString(PyExc_ValueError,
     909             :                         "read length must be positive");
     910           0 :         return NULL;
     911             :     }
     912           0 :     if (n == 0)
     913           0 :         return PyBytes_FromStringAndSize(NULL, 0);
     914             : 
     915             :     /* Return up to n bytes.  If at least one byte is buffered, we
     916             :        only return buffered bytes.  Otherwise, we do one raw read. */
     917             : 
     918           0 :     have = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
     919           0 :     if (have > 0) {
     920           0 :         n = Py_MIN(have, n);
     921           0 :         res = _bufferedreader_read_fast(self, n);
     922             :         assert(res != Py_None);
     923           0 :         return res;
     924             :     }
     925           0 :     res = PyBytes_FromStringAndSize(NULL, n);
     926           0 :     if (res == NULL)
     927           0 :         return NULL;
     928           0 :     if (!ENTER_BUFFERED(self)) {
     929           0 :         Py_DECREF(res);
     930           0 :         return NULL;
     931             :     }
     932           0 :     _bufferedreader_reset_buf(self);
     933           0 :     r = _bufferedreader_raw_read(self, PyBytes_AS_STRING(res), n);
     934           0 :     LEAVE_BUFFERED(self)
     935           0 :     if (r == -1) {
     936           0 :         Py_DECREF(res);
     937           0 :         return NULL;
     938             :     }
     939           0 :     if (r == -2)
     940           0 :         r = 0;
     941           0 :     if (n > r)
     942           0 :         _PyBytes_Resize(&res, r);
     943           0 :     return res;
     944             : }
     945             : 
     946             : static PyObject *
     947           0 : buffered_readinto(buffered *self, PyObject *args)
     948             : {
     949             :     Py_buffer buf;
     950           0 :     Py_ssize_t n, written = 0, remaining;
     951           0 :     PyObject *res = NULL;
     952             : 
     953           0 :     CHECK_INITIALIZED(self)
     954             : 
     955           0 :     if (!PyArg_ParseTuple(args, "w*:readinto", &buf))
     956           0 :         return NULL;
     957             : 
     958           0 :     n = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
     959           0 :     if (n > 0) {
     960           0 :         if (n >= buf.len) {
     961           0 :             memcpy(buf.buf, self->buffer + self->pos, buf.len);
     962           0 :             self->pos += buf.len;
     963           0 :             res = PyLong_FromSsize_t(buf.len);
     964           0 :             goto end_unlocked;
     965             :         }
     966           0 :         memcpy(buf.buf, self->buffer + self->pos, n);
     967           0 :         self->pos += n;
     968           0 :         written = n;
     969             :     }
     970             : 
     971           0 :     if (!ENTER_BUFFERED(self))
     972             :         goto end_unlocked;
     973             : 
     974           0 :     if (self->writable) {
     975           0 :         res = buffered_flush_and_rewind_unlocked(self);
     976           0 :         if (res == NULL)
     977           0 :             goto end;
     978           0 :         Py_CLEAR(res);
     979             :     }
     980             : 
     981           0 :     _bufferedreader_reset_buf(self);
     982           0 :     self->pos = 0;
     983             : 
     984           0 :     for (remaining = buf.len - written;
     985             :          remaining > 0;
     986           0 :          written += n, remaining -= n) {
     987             :         /* If remaining bytes is larger than internal buffer size, copy
     988             :          * directly into caller's buffer. */
     989           0 :         if (remaining > self->buffer_size) {
     990           0 :             n = _bufferedreader_raw_read(self, (char *) buf.buf + written,
     991             :                                          remaining);
     992             :         }
     993             :         else {
     994           0 :             n = _bufferedreader_fill_buffer(self);
     995           0 :             if (n > 0) {
     996           0 :                 if (n > remaining)
     997           0 :                     n = remaining;
     998           0 :                 memcpy((char *) buf.buf + written,
     999           0 :                        self->buffer + self->pos, n);
    1000           0 :                 self->pos += n;
    1001           0 :                 continue; /* short circuit */
    1002             :             }
    1003             :         }
    1004           0 :         if (n == 0 || (n == -2 && written > 0))
    1005             :             break;
    1006           0 :         if (n < 0) {
    1007           0 :             if (n == -2) {
    1008           0 :                 Py_INCREF(Py_None);
    1009           0 :                 res = Py_None;
    1010             :             }
    1011           0 :             goto end;
    1012             :         }
    1013             :     }
    1014           0 :     res = PyLong_FromSsize_t(written);
    1015             : 
    1016             : end:
    1017           0 :     LEAVE_BUFFERED(self);
    1018             : end_unlocked:
    1019           0 :     PyBuffer_Release(&buf);
    1020           0 :     return res;
    1021             : }
    1022             : 
    1023             : static PyObject *
    1024           0 : _buffered_readline(buffered *self, Py_ssize_t limit)
    1025             : {
    1026           0 :     PyObject *res = NULL;
    1027           0 :     PyObject *chunks = NULL;
    1028           0 :     Py_ssize_t n, written = 0;
    1029             :     const char *start, *s, *end;
    1030             : 
    1031           0 :     CHECK_CLOSED(self, "readline of closed file")
    1032             : 
    1033             :     /* First, try to find a line in the buffer. This can run unlocked because
    1034             :        the calls to the C API are simple enough that they can't trigger
    1035             :        any thread switch. */
    1036           0 :     n = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
    1037           0 :     if (limit >= 0 && n > limit)
    1038           0 :         n = limit;
    1039           0 :     start = self->buffer + self->pos;
    1040           0 :     s = memchr(start, '\n', n);
    1041           0 :     if (s != NULL) {
    1042           0 :         res = PyBytes_FromStringAndSize(start, s - start + 1);
    1043           0 :         if (res != NULL)
    1044           0 :             self->pos += s - start + 1;
    1045           0 :         goto end_unlocked;
    1046             :     }
    1047           0 :     if (n == limit) {
    1048           0 :         res = PyBytes_FromStringAndSize(start, n);
    1049           0 :         if (res != NULL)
    1050           0 :             self->pos += n;
    1051           0 :         goto end_unlocked;
    1052             :     }
    1053             : 
    1054           0 :     if (!ENTER_BUFFERED(self))
    1055             :         goto end_unlocked;
    1056             : 
    1057             :     /* Now we try to get some more from the raw stream */
    1058           0 :     chunks = PyList_New(0);
    1059           0 :     if (chunks == NULL)
    1060           0 :         goto end;
    1061           0 :     if (n > 0) {
    1062           0 :         res = PyBytes_FromStringAndSize(start, n);
    1063           0 :         if (res == NULL)
    1064           0 :             goto end;
    1065           0 :         if (PyList_Append(chunks, res) < 0) {
    1066           0 :             Py_CLEAR(res);
    1067           0 :             goto end;
    1068             :         }
    1069           0 :         Py_CLEAR(res);
    1070           0 :         written += n;
    1071           0 :         self->pos += n;
    1072           0 :         if (limit >= 0)
    1073           0 :             limit -= n;
    1074             :     }
    1075           0 :     if (self->writable) {
    1076           0 :         PyObject *r = buffered_flush_and_rewind_unlocked(self);
    1077           0 :         if (r == NULL)
    1078           0 :             goto end;
    1079           0 :         Py_DECREF(r);
    1080             :     }
    1081             : 
    1082             :     for (;;) {
    1083           0 :         _bufferedreader_reset_buf(self);
    1084           0 :         n = _bufferedreader_fill_buffer(self);
    1085           0 :         if (n == -1)
    1086           0 :             goto end;
    1087           0 :         if (n <= 0)
    1088           0 :             break;
    1089           0 :         if (limit >= 0 && n > limit)
    1090           0 :             n = limit;
    1091           0 :         start = self->buffer;
    1092           0 :         end = start + n;
    1093           0 :         s = start;
    1094           0 :         while (s < end) {
    1095           0 :             if (*s++ == '\n') {
    1096           0 :                 res = PyBytes_FromStringAndSize(start, s - start);
    1097           0 :                 if (res == NULL)
    1098           0 :                     goto end;
    1099           0 :                 self->pos = s - start;
    1100           0 :                 goto found;
    1101             :             }
    1102             :         }
    1103           0 :         res = PyBytes_FromStringAndSize(start, n);
    1104           0 :         if (res == NULL)
    1105           0 :             goto end;
    1106           0 :         if (n == limit) {
    1107           0 :             self->pos = n;
    1108           0 :             break;
    1109             :         }
    1110           0 :         if (PyList_Append(chunks, res) < 0) {
    1111           0 :             Py_CLEAR(res);
    1112           0 :             goto end;
    1113             :         }
    1114           0 :         Py_CLEAR(res);
    1115           0 :         written += n;
    1116           0 :         if (limit >= 0)
    1117           0 :             limit -= n;
    1118           0 :     }
    1119             : found:
    1120           0 :     if (res != NULL && PyList_Append(chunks, res) < 0) {
    1121           0 :         Py_CLEAR(res);
    1122           0 :         goto end;
    1123             :     }
    1124           0 :     Py_CLEAR(res);
    1125           0 :     res = _PyBytes_Join(_PyIO_empty_bytes, chunks);
    1126             : 
    1127             : end:
    1128           0 :     LEAVE_BUFFERED(self)
    1129             : end_unlocked:
    1130           0 :     Py_XDECREF(chunks);
    1131           0 :     return res;
    1132             : }
    1133             : 
    1134             : static PyObject *
    1135           0 : buffered_readline(buffered *self, PyObject *args)
    1136             : {
    1137           0 :     Py_ssize_t limit = -1;
    1138             : 
    1139           0 :     CHECK_INITIALIZED(self)
    1140           0 :     if (!PyArg_ParseTuple(args, "|O&:readline", &_PyIO_ConvertSsize_t, &limit))
    1141           0 :         return NULL;
    1142           0 :     return _buffered_readline(self, limit);
    1143             : }
    1144             : 
    1145             : 
    1146             : static PyObject *
    1147           0 : buffered_tell(buffered *self, PyObject *args)
    1148             : {
    1149             :     Py_off_t pos;
    1150             : 
    1151           0 :     CHECK_INITIALIZED(self)
    1152           0 :     pos = _buffered_raw_tell(self);
    1153           0 :     if (pos == -1)
    1154           0 :         return NULL;
    1155           0 :     pos -= RAW_OFFSET(self);
    1156             :     /* TODO: sanity check (pos >= 0) */
    1157           0 :     return PyLong_FromOff_t(pos);
    1158             : }
    1159             : 
    1160             : static PyObject *
    1161           0 : buffered_seek(buffered *self, PyObject *args)
    1162             : {
    1163             :     Py_off_t target, n;
    1164           0 :     int whence = 0;
    1165           0 :     PyObject *targetobj, *res = NULL;
    1166             : 
    1167           0 :     CHECK_INITIALIZED(self)
    1168           0 :     if (!PyArg_ParseTuple(args, "O|i:seek", &targetobj, &whence)) {
    1169           0 :         return NULL;
    1170             :     }
    1171             : 
    1172             :     /* Do some error checking instead of trusting OS 'seek()'
    1173             :     ** error detection, just in case.
    1174             :     */
    1175           0 :     if ((whence < 0 || whence >2)
    1176             : #ifdef SEEK_HOLE
    1177           0 :         && (whence != SEEK_HOLE)
    1178             : #endif
    1179             : #ifdef SEEK_DATA
    1180           0 :         && (whence != SEEK_DATA)
    1181             : #endif
    1182             :         ) {
    1183           0 :         PyErr_Format(PyExc_ValueError,
    1184             :                      "whence value %d unsupported", whence);
    1185           0 :         return NULL;
    1186             :     }
    1187             : 
    1188           0 :     CHECK_CLOSED(self, "seek of closed file")
    1189             : 
    1190           0 :     if (_PyIOBase_check_seekable(self->raw, Py_True) == NULL)
    1191           0 :         return NULL;
    1192             : 
    1193           0 :     target = PyNumber_AsOff_t(targetobj, PyExc_ValueError);
    1194           0 :     if (target == -1 && PyErr_Occurred())
    1195           0 :         return NULL;
    1196             : 
    1197             :     /* SEEK_SET and SEEK_CUR are special because we could seek inside the
    1198             :        buffer. Other whence values must be managed without this optimization.
    1199             :        Some Operating Systems can provide additional values, like
    1200             :        SEEK_HOLE/SEEK_DATA. */
    1201           0 :     if (((whence == 0) || (whence == 1)) && self->readable) {
    1202             :         Py_off_t current, avail;
    1203             :         /* Check if seeking leaves us inside the current buffer,
    1204             :            so as to return quickly if possible. Also, we needn't take the
    1205             :            lock in this fast path.
    1206             :            Don't know how to do that when whence == 2, though. */
    1207             :         /* NOTE: RAW_TELL() can release the GIL but the object is in a stable
    1208             :            state at this point. */
    1209           0 :         current = RAW_TELL(self);
    1210           0 :         avail = READAHEAD(self);
    1211           0 :         if (avail > 0) {
    1212             :             Py_off_t offset;
    1213           0 :             if (whence == 0)
    1214           0 :                 offset = target - (current - RAW_OFFSET(self));
    1215             :             else
    1216           0 :                 offset = target;
    1217           0 :             if (offset >= -self->pos && offset <= avail) {
    1218           0 :                 self->pos += offset;
    1219           0 :                 return PyLong_FromOff_t(current - avail + offset);
    1220             :             }
    1221             :         }
    1222             :     }
    1223             : 
    1224           0 :     if (!ENTER_BUFFERED(self))
    1225           0 :         return NULL;
    1226             : 
    1227             :     /* Fallback: invoke raw seek() method and clear buffer */
    1228           0 :     if (self->writable) {
    1229           0 :         res = _bufferedwriter_flush_unlocked(self);
    1230           0 :         if (res == NULL)
    1231           0 :             goto end;
    1232           0 :         Py_CLEAR(res);
    1233           0 :         _bufferedwriter_reset_buf(self);
    1234             :     }
    1235             : 
    1236             :     /* TODO: align on block boundary and read buffer if needed? */
    1237           0 :     if (whence == 1)
    1238           0 :         target -= RAW_OFFSET(self);
    1239           0 :     n = _buffered_raw_seek(self, target, whence);
    1240           0 :     if (n == -1)
    1241           0 :         goto end;
    1242           0 :     self->raw_pos = -1;
    1243           0 :     res = PyLong_FromOff_t(n);
    1244           0 :     if (res != NULL && self->readable)
    1245           0 :         _bufferedreader_reset_buf(self);
    1246             : 
    1247             : end:
    1248           0 :     LEAVE_BUFFERED(self)
    1249           0 :     return res;
    1250             : }
    1251             : 
    1252             : static PyObject *
    1253           0 : buffered_truncate(buffered *self, PyObject *args)
    1254             : {
    1255           0 :     PyObject *pos = Py_None;
    1256           0 :     PyObject *res = NULL;
    1257             : 
    1258           0 :     CHECK_INITIALIZED(self)
    1259           0 :     if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
    1260           0 :         return NULL;
    1261             :     }
    1262             : 
    1263           0 :     if (!ENTER_BUFFERED(self))
    1264           0 :         return NULL;
    1265             : 
    1266           0 :     if (self->writable) {
    1267           0 :         res = buffered_flush_and_rewind_unlocked(self);
    1268           0 :         if (res == NULL)
    1269           0 :             goto end;
    1270           0 :         Py_CLEAR(res);
    1271             :     }
    1272           0 :     res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_truncate, pos, NULL);
    1273           0 :     if (res == NULL)
    1274           0 :         goto end;
    1275             :     /* Reset cached position */
    1276           0 :     if (_buffered_raw_tell(self) == -1)
    1277           0 :         PyErr_Clear();
    1278             : 
    1279             : end:
    1280           0 :     LEAVE_BUFFERED(self)
    1281           0 :     return res;
    1282             : }
    1283             : 
    1284             : static PyObject *
    1285           0 : buffered_iternext(buffered *self)
    1286             : {
    1287             :     PyObject *line;
    1288             :     PyTypeObject *tp;
    1289             : 
    1290           0 :     CHECK_INITIALIZED(self);
    1291             : 
    1292           0 :     tp = Py_TYPE(self);
    1293           0 :     if (tp == &PyBufferedReader_Type ||
    1294             :         tp == &PyBufferedRandom_Type) {
    1295             :         /* Skip method call overhead for speed */
    1296           0 :         line = _buffered_readline(self, -1);
    1297             :     }
    1298             :     else {
    1299           0 :         line = PyObject_CallMethodObjArgs((PyObject *)self,
    1300             :                                            _PyIO_str_readline, NULL);
    1301           0 :         if (line && !PyBytes_Check(line)) {
    1302           0 :             PyErr_Format(PyExc_IOError,
    1303             :                          "readline() should have returned a bytes object, "
    1304           0 :                          "not '%.200s'", Py_TYPE(line)->tp_name);
    1305           0 :             Py_DECREF(line);
    1306           0 :             return NULL;
    1307             :         }
    1308             :     }
    1309             : 
    1310           0 :     if (line == NULL)
    1311           0 :         return NULL;
    1312             : 
    1313           0 :     if (PyBytes_GET_SIZE(line) == 0) {
    1314             :         /* Reached EOF or would have blocked */
    1315           0 :         Py_DECREF(line);
    1316           0 :         return NULL;
    1317             :     }
    1318             : 
    1319           0 :     return line;
    1320             : }
    1321             : 
    1322             : static PyObject *
    1323           0 : buffered_repr(buffered *self)
    1324             : {
    1325             :     PyObject *nameobj, *res;
    1326             : 
    1327           0 :     nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name);
    1328           0 :     if (nameobj == NULL) {
    1329           0 :         if (PyErr_ExceptionMatches(PyExc_AttributeError))
    1330           0 :             PyErr_Clear();
    1331             :         else
    1332           0 :             return NULL;
    1333           0 :         res = PyUnicode_FromFormat("<%s>", Py_TYPE(self)->tp_name);
    1334             :     }
    1335             :     else {
    1336           0 :         res = PyUnicode_FromFormat("<%s name=%R>",
    1337           0 :                                    Py_TYPE(self)->tp_name, nameobj);
    1338           0 :         Py_DECREF(nameobj);
    1339             :     }
    1340           0 :     return res;
    1341             : }
    1342             : 
    1343             : /*
    1344             :  * class BufferedReader
    1345             :  */
    1346             : 
    1347             : PyDoc_STRVAR(bufferedreader_doc,
    1348             :              "Create a new buffered reader using the given readable raw IO object.");
    1349             : 
    1350           3 : static void _bufferedreader_reset_buf(buffered *self)
    1351             : {
    1352           3 :     self->read_end = -1;
    1353           3 : }
    1354             : 
    1355             : static int
    1356           2 : bufferedreader_init(buffered *self, PyObject *args, PyObject *kwds)
    1357             : {
    1358           2 :     char *kwlist[] = {"raw", "buffer_size", NULL};
    1359           2 :     Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
    1360             :     PyObject *raw;
    1361             : 
    1362           2 :     self->ok = 0;
    1363           2 :     self->detached = 0;
    1364             : 
    1365           2 :     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedReader", kwlist,
    1366             :                                      &raw, &buffer_size)) {
    1367           0 :         return -1;
    1368             :     }
    1369             : 
    1370           2 :     if (_PyIOBase_check_readable(raw, Py_True) == NULL)
    1371           0 :         return -1;
    1372             : 
    1373           2 :     Py_CLEAR(self->raw);
    1374           2 :     Py_INCREF(raw);
    1375           2 :     self->raw = raw;
    1376           2 :     self->buffer_size = buffer_size;
    1377           2 :     self->readable = 1;
    1378           2 :     self->writable = 0;
    1379             : 
    1380           2 :     if (_buffered_init(self) < 0)
    1381           0 :         return -1;
    1382           2 :     _bufferedreader_reset_buf(self);
    1383             : 
    1384           4 :     self->fast_closed_checks = (Py_TYPE(self) == &PyBufferedReader_Type &&
    1385           2 :                                 Py_TYPE(raw) == &PyFileIO_Type);
    1386             : 
    1387           2 :     self->ok = 1;
    1388           2 :     return 0;
    1389             : }
    1390             : 
    1391             : static Py_ssize_t
    1392           0 : _bufferedreader_raw_read(buffered *self, char *start, Py_ssize_t len)
    1393             : {
    1394             :     Py_buffer buf;
    1395             :     PyObject *memobj, *res;
    1396             :     Py_ssize_t n;
    1397             :     /* NOTE: the buffer needn't be released as its object is NULL. */
    1398           0 :     if (PyBuffer_FillInfo(&buf, NULL, start, len, 0, PyBUF_CONTIG) == -1)
    1399           0 :         return -1;
    1400           0 :     memobj = PyMemoryView_FromBuffer(&buf);
    1401           0 :     if (memobj == NULL)
    1402           0 :         return -1;
    1403             :     /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals() when EINTR
    1404             :        occurs so we needn't do it ourselves.
    1405             :        We then retry reading, ignoring the signal if no handler has
    1406             :        raised (see issue #10956).
    1407             :     */
    1408             :     do {
    1409           0 :         res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readinto, memobj, NULL);
    1410           0 :     } while (res == NULL && _PyIO_trap_eintr());
    1411           0 :     Py_DECREF(memobj);
    1412           0 :     if (res == NULL)
    1413           0 :         return -1;
    1414           0 :     if (res == Py_None) {
    1415             :         /* Non-blocking stream would have blocked. Special return code! */
    1416           0 :         Py_DECREF(res);
    1417           0 :         return -2;
    1418             :     }
    1419           0 :     n = PyNumber_AsSsize_t(res, PyExc_ValueError);
    1420           0 :     Py_DECREF(res);
    1421           0 :     if (n < 0 || n > len) {
    1422           0 :         PyErr_Format(PyExc_IOError,
    1423             :                      "raw readinto() returned invalid length %zd "
    1424             :                      "(should have been between 0 and %zd)", n, len);
    1425           0 :         return -1;
    1426             :     }
    1427           0 :     if (n > 0 && self->abs_pos != -1)
    1428           0 :         self->abs_pos += n;
    1429           0 :     return n;
    1430             : }
    1431             : 
    1432             : static Py_ssize_t
    1433           0 : _bufferedreader_fill_buffer(buffered *self)
    1434             : {
    1435             :     Py_ssize_t start, len, n;
    1436           0 :     if (VALID_READ_BUFFER(self))
    1437           0 :         start = Py_SAFE_DOWNCAST(self->read_end, Py_off_t, Py_ssize_t);
    1438             :     else
    1439           0 :         start = 0;
    1440           0 :     len = self->buffer_size - start;
    1441           0 :     n = _bufferedreader_raw_read(self, self->buffer + start, len);
    1442           0 :     if (n <= 0)
    1443           0 :         return n;
    1444           0 :     self->read_end = start + n;
    1445           0 :     self->raw_pos = start + n;
    1446           0 :     return n;
    1447             : }
    1448             : 
    1449             : static PyObject *
    1450           1 : _bufferedreader_read_all(buffered *self)
    1451             : {
    1452             :     Py_ssize_t current_size;
    1453           1 :     PyObject *res, *data = NULL, *chunk, *chunks;
    1454             : 
    1455             :     /* First copy what we have in the current buffer. */
    1456           1 :     current_size = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
    1457           1 :     if (current_size) {
    1458           0 :         data = PyBytes_FromStringAndSize(
    1459           0 :             self->buffer + self->pos, current_size);
    1460           0 :         if (data == NULL)
    1461           0 :             return NULL;
    1462           0 :         self->pos += current_size;
    1463             :     }
    1464             :     /* We're going past the buffer's bounds, flush it */
    1465           1 :     if (self->writable) {
    1466           0 :         res = buffered_flush_and_rewind_unlocked(self);
    1467           0 :         if (res == NULL)
    1468           0 :             return NULL;
    1469           0 :         Py_CLEAR(res);
    1470             :     }
    1471           1 :     _bufferedreader_reset_buf(self);
    1472             : 
    1473           1 :     if (PyObject_HasAttr(self->raw, _PyIO_str_readall)) {
    1474           1 :         chunk = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readall, NULL);
    1475           1 :         if (chunk == NULL)
    1476           0 :             return NULL;
    1477           1 :         if (chunk != Py_None && !PyBytes_Check(chunk)) {
    1478           0 :             Py_XDECREF(data);
    1479           0 :             Py_DECREF(chunk);
    1480           0 :             PyErr_SetString(PyExc_TypeError, "readall() should return bytes");
    1481           0 :             return NULL;
    1482             :         }
    1483           1 :         if (chunk == Py_None) {
    1484           0 :             if (current_size == 0)
    1485           0 :                 return chunk;
    1486             :             else {
    1487           0 :                 Py_DECREF(chunk);
    1488           0 :                 return data;
    1489             :             }
    1490             :         }
    1491           1 :         else if (current_size) {
    1492           0 :             PyBytes_Concat(&data, chunk);
    1493           0 :             Py_DECREF(chunk);
    1494           0 :             if (data == NULL)
    1495           0 :                 return NULL;
    1496           0 :             return data;
    1497             :         } else
    1498           1 :             return chunk;
    1499             :     }
    1500             : 
    1501           0 :     chunks = PyList_New(0);
    1502           0 :     if (chunks == NULL) {
    1503           0 :         Py_XDECREF(data);
    1504           0 :         return NULL;
    1505             :     }
    1506             : 
    1507             :     while (1) {
    1508           0 :         if (data) {
    1509           0 :             if (PyList_Append(chunks, data) < 0) {
    1510           0 :                 Py_DECREF(data);
    1511           0 :                 Py_DECREF(chunks);
    1512           0 :                 return NULL;
    1513             :             }
    1514           0 :             Py_DECREF(data);
    1515             :         }
    1516             : 
    1517             :         /* Read until EOF or until read() would block. */
    1518           0 :         data = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_read, NULL);
    1519           0 :         if (data == NULL) {
    1520           0 :             Py_DECREF(chunks);
    1521           0 :             return NULL;
    1522             :         }
    1523           0 :         if (data != Py_None && !PyBytes_Check(data)) {
    1524           0 :             Py_DECREF(data);
    1525           0 :             Py_DECREF(chunks);
    1526           0 :             PyErr_SetString(PyExc_TypeError, "read() should return bytes");
    1527           0 :             return NULL;
    1528             :         }
    1529           0 :         if (data == Py_None || PyBytes_GET_SIZE(data) == 0) {
    1530           0 :             if (current_size == 0) {
    1531           0 :                 Py_DECREF(chunks);
    1532           0 :                 return data;
    1533             :             }
    1534             :             else {
    1535           0 :                 res = _PyBytes_Join(_PyIO_empty_bytes, chunks);
    1536           0 :                 Py_DECREF(data);
    1537           0 :                 Py_DECREF(chunks);
    1538           0 :                 return res;
    1539             :             }
    1540             :         }
    1541           0 :         current_size += PyBytes_GET_SIZE(data);
    1542           0 :         if (self->abs_pos != -1)
    1543           0 :             self->abs_pos += PyBytes_GET_SIZE(data);
    1544           0 :     }
    1545             : }
    1546             : 
    1547             : /* Read n bytes from the buffer if it can, otherwise return None.
    1548             :    This function is simple enough that it can run unlocked. */
    1549             : static PyObject *
    1550           0 : _bufferedreader_read_fast(buffered *self, Py_ssize_t n)
    1551             : {
    1552             :     Py_ssize_t current_size;
    1553             : 
    1554           0 :     current_size = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
    1555           0 :     if (n <= current_size) {
    1556             :         /* Fast path: the data to read is fully buffered. */
    1557           0 :         PyObject *res = PyBytes_FromStringAndSize(self->buffer + self->pos, n);
    1558           0 :         if (res != NULL)
    1559           0 :             self->pos += n;
    1560           0 :         return res;
    1561             :     }
    1562           0 :     Py_RETURN_NONE;
    1563             : }
    1564             : 
    1565             : /* Generic read function: read from the stream until enough bytes are read,
    1566             :  * or until an EOF occurs or until read() would block.
    1567             :  */
    1568             : static PyObject *
    1569           0 : _bufferedreader_read_generic(buffered *self, Py_ssize_t n)
    1570             : {
    1571           0 :     PyObject *res = NULL;
    1572             :     Py_ssize_t current_size, remaining, written;
    1573             :     char *out;
    1574             : 
    1575           0 :     current_size = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
    1576           0 :     if (n <= current_size)
    1577           0 :         return _bufferedreader_read_fast(self, n);
    1578             : 
    1579           0 :     res = PyBytes_FromStringAndSize(NULL, n);
    1580           0 :     if (res == NULL)
    1581           0 :         goto error;
    1582           0 :     out = PyBytes_AS_STRING(res);
    1583           0 :     remaining = n;
    1584           0 :     written = 0;
    1585           0 :     if (current_size > 0) {
    1586           0 :         memcpy(out, self->buffer + self->pos, current_size);
    1587           0 :         remaining -= current_size;
    1588           0 :         written += current_size;
    1589           0 :         self->pos += current_size;
    1590             :     }
    1591             :     /* Flush the write buffer if necessary */
    1592           0 :     if (self->writable) {
    1593           0 :         PyObject *r = buffered_flush_and_rewind_unlocked(self);
    1594           0 :         if (r == NULL)
    1595           0 :             goto error;
    1596           0 :         Py_DECREF(r);
    1597             :     }
    1598           0 :     _bufferedreader_reset_buf(self);
    1599           0 :     while (remaining > 0) {
    1600             :         /* We want to read a whole block at the end into buffer.
    1601             :            If we had readv() we could do this in one pass. */
    1602           0 :         Py_ssize_t r = MINUS_LAST_BLOCK(self, remaining);
    1603           0 :         if (r == 0)
    1604           0 :             break;
    1605           0 :         r = _bufferedreader_raw_read(self, out + written, r);
    1606           0 :         if (r == -1)
    1607           0 :             goto error;
    1608           0 :         if (r == 0 || r == -2) {
    1609             :             /* EOF occurred or read() would block. */
    1610           0 :             if (r == 0 || written > 0) {
    1611           0 :                 if (_PyBytes_Resize(&res, written))
    1612           0 :                     goto error;
    1613           0 :                 return res;
    1614             :             }
    1615           0 :             Py_DECREF(res);
    1616           0 :             Py_INCREF(Py_None);
    1617           0 :             return Py_None;
    1618             :         }
    1619           0 :         remaining -= r;
    1620           0 :         written += r;
    1621             :     }
    1622             :     assert(remaining <= self->buffer_size);
    1623           0 :     self->pos = 0;
    1624           0 :     self->raw_pos = 0;
    1625           0 :     self->read_end = 0;
    1626             :     /* NOTE: when the read is satisfied, we avoid issuing any additional
    1627             :        reads, which could block indefinitely (e.g. on a socket).
    1628             :        See issue #9550. */
    1629           0 :     while (remaining > 0 && self->read_end < self->buffer_size) {
    1630           0 :         Py_ssize_t r = _bufferedreader_fill_buffer(self);
    1631           0 :         if (r == -1)
    1632           0 :             goto error;
    1633           0 :         if (r == 0 || r == -2) {
    1634             :             /* EOF occurred or read() would block. */
    1635           0 :             if (r == 0 || written > 0) {
    1636           0 :                 if (_PyBytes_Resize(&res, written))
    1637           0 :                     goto error;
    1638           0 :                 return res;
    1639             :             }
    1640           0 :             Py_DECREF(res);
    1641           0 :             Py_INCREF(Py_None);
    1642           0 :             return Py_None;
    1643             :         }
    1644           0 :         if (remaining > r) {
    1645           0 :             memcpy(out + written, self->buffer + self->pos, r);
    1646           0 :             written += r;
    1647           0 :             self->pos += r;
    1648           0 :             remaining -= r;
    1649             :         }
    1650           0 :         else if (remaining > 0) {
    1651           0 :             memcpy(out + written, self->buffer + self->pos, remaining);
    1652           0 :             written += remaining;
    1653           0 :             self->pos += remaining;
    1654           0 :             remaining = 0;
    1655             :         }
    1656           0 :         if (remaining == 0)
    1657           0 :             break;
    1658             :     }
    1659             : 
    1660           0 :     return res;
    1661             : 
    1662             : error:
    1663           0 :     Py_XDECREF(res);
    1664           0 :     return NULL;
    1665             : }
    1666             : 
    1667             : static PyObject *
    1668           0 : _bufferedreader_peek_unlocked(buffered *self)
    1669             : {
    1670             :     Py_ssize_t have, r;
    1671             : 
    1672           0 :     have = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
    1673             :     /* Constraints:
    1674             :        1. we don't want to advance the file position.
    1675             :        2. we don't want to lose block alignment, so we can't shift the buffer
    1676             :           to make some place.
    1677             :        Therefore, we either return `have` bytes (if > 0), or a full buffer.
    1678             :     */
    1679           0 :     if (have > 0) {
    1680           0 :         return PyBytes_FromStringAndSize(self->buffer + self->pos, have);
    1681             :     }
    1682             : 
    1683             :     /* Fill the buffer from the raw stream, and copy it to the result. */
    1684           0 :     _bufferedreader_reset_buf(self);
    1685           0 :     r = _bufferedreader_fill_buffer(self);
    1686           0 :     if (r == -1)
    1687           0 :         return NULL;
    1688           0 :     if (r == -2)
    1689           0 :         r = 0;
    1690           0 :     self->pos = 0;
    1691           0 :     return PyBytes_FromStringAndSize(self->buffer, r);
    1692             : }
    1693             : 
    1694             : static PyMethodDef bufferedreader_methods[] = {
    1695             :     /* BufferedIOMixin methods */
    1696             :     {"detach", (PyCFunction)buffered_detach, METH_NOARGS},
    1697             :     {"flush", (PyCFunction)buffered_simple_flush, METH_NOARGS},
    1698             :     {"close", (PyCFunction)buffered_close, METH_NOARGS},
    1699             :     {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS},
    1700             :     {"readable", (PyCFunction)buffered_readable, METH_NOARGS},
    1701             :     {"writable", (PyCFunction)buffered_writable, METH_NOARGS},
    1702             :     {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
    1703             :     {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
    1704             :     {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
    1705             :     {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
    1706             : 
    1707             :     {"read", (PyCFunction)buffered_read, METH_VARARGS},
    1708             :     {"peek", (PyCFunction)buffered_peek, METH_VARARGS},
    1709             :     {"read1", (PyCFunction)buffered_read1, METH_VARARGS},
    1710             :     {"readinto", (PyCFunction)buffered_readinto, METH_VARARGS},
    1711             :     {"readline", (PyCFunction)buffered_readline, METH_VARARGS},
    1712             :     {"seek", (PyCFunction)buffered_seek, METH_VARARGS},
    1713             :     {"tell", (PyCFunction)buffered_tell, METH_NOARGS},
    1714             :     {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS},
    1715             :     {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS},
    1716             :     {NULL, NULL}
    1717             : };
    1718             : 
    1719             : static PyMemberDef bufferedreader_members[] = {
    1720             :     {"raw", T_OBJECT, offsetof(buffered, raw), READONLY},
    1721             :     {NULL}
    1722             : };
    1723             : 
    1724             : static PyGetSetDef bufferedreader_getset[] = {
    1725             :     {"closed", (getter)buffered_closed_get, NULL, NULL},
    1726             :     {"name", (getter)buffered_name_get, NULL, NULL},
    1727             :     {"mode", (getter)buffered_mode_get, NULL, NULL},
    1728             :     {NULL}
    1729             : };
    1730             : 
    1731             : 
    1732             : PyTypeObject PyBufferedReader_Type = {
    1733             :     PyVarObject_HEAD_INIT(NULL, 0)
    1734             :     "_io.BufferedReader",       /*tp_name*/
    1735             :     sizeof(buffered),           /*tp_basicsize*/
    1736             :     0,                          /*tp_itemsize*/
    1737             :     (destructor)buffered_dealloc,     /*tp_dealloc*/
    1738             :     0,                          /*tp_print*/
    1739             :     0,                          /*tp_getattr*/
    1740             :     0,                          /*tp_setattr*/
    1741             :     0,                          /*tp_compare */
    1742             :     (reprfunc)buffered_repr,    /*tp_repr*/
    1743             :     0,                          /*tp_as_number*/
    1744             :     0,                          /*tp_as_sequence*/
    1745             :     0,                          /*tp_as_mapping*/
    1746             :     0,                          /*tp_hash */
    1747             :     0,                          /*tp_call*/
    1748             :     0,                          /*tp_str*/
    1749             :     0,                          /*tp_getattro*/
    1750             :     0,                          /*tp_setattro*/
    1751             :     0,                          /*tp_as_buffer*/
    1752             :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
    1753             :             | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
    1754             :     bufferedreader_doc,         /* tp_doc */
    1755             :     (traverseproc)buffered_traverse, /* tp_traverse */
    1756             :     (inquiry)buffered_clear,    /* tp_clear */
    1757             :     0,                          /* tp_richcompare */
    1758             :     offsetof(buffered, weakreflist), /*tp_weaklistoffset*/
    1759             :     0,                          /* tp_iter */
    1760             :     (iternextfunc)buffered_iternext, /* tp_iternext */
    1761             :     bufferedreader_methods,     /* tp_methods */
    1762             :     bufferedreader_members,     /* tp_members */
    1763             :     bufferedreader_getset,      /* tp_getset */
    1764             :     0,                          /* tp_base */
    1765             :     0,                          /* tp_dict */
    1766             :     0,                          /* tp_descr_get */
    1767             :     0,                          /* tp_descr_set */
    1768             :     offsetof(buffered, dict), /* tp_dictoffset */
    1769             :     (initproc)bufferedreader_init, /* tp_init */
    1770             :     0,                          /* tp_alloc */
    1771             :     PyType_GenericNew,          /* tp_new */
    1772             : };
    1773             : 
    1774             : 
    1775             : 
    1776             : /*
    1777             :  * class BufferedWriter
    1778             :  */
    1779             : PyDoc_STRVAR(bufferedwriter_doc,
    1780             :     "A buffer for a writeable sequential RawIO object.\n"
    1781             :     "\n"
    1782             :     "The constructor creates a BufferedWriter for the given writeable raw\n"
    1783             :     "stream. If the buffer_size is not given, it defaults to\n"
    1784             :     "DEFAULT_BUFFER_SIZE.\n"
    1785             :     );
    1786             : 
    1787             : static void
    1788           2 : _bufferedwriter_reset_buf(buffered *self)
    1789             : {
    1790           2 :     self->write_pos = 0;
    1791           2 :     self->write_end = -1;
    1792           2 : }
    1793             : 
    1794             : static int
    1795           2 : bufferedwriter_init(buffered *self, PyObject *args, PyObject *kwds)
    1796             : {
    1797           2 :     char *kwlist[] = {"raw", "buffer_size", NULL};
    1798           2 :     Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
    1799             :     PyObject *raw;
    1800             : 
    1801           2 :     self->ok = 0;
    1802           2 :     self->detached = 0;
    1803             : 
    1804           2 :     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedReader", kwlist,
    1805             :                                      &raw, &buffer_size)) {
    1806           0 :         return -1;
    1807             :     }
    1808             : 
    1809           2 :     if (_PyIOBase_check_writable(raw, Py_True) == NULL)
    1810           0 :         return -1;
    1811             : 
    1812           2 :     Py_CLEAR(self->raw);
    1813           2 :     Py_INCREF(raw);
    1814           2 :     self->raw = raw;
    1815           2 :     self->readable = 0;
    1816           2 :     self->writable = 1;
    1817             : 
    1818           2 :     self->buffer_size = buffer_size;
    1819           2 :     if (_buffered_init(self) < 0)
    1820           0 :         return -1;
    1821           2 :     _bufferedwriter_reset_buf(self);
    1822           2 :     self->pos = 0;
    1823             : 
    1824           4 :     self->fast_closed_checks = (Py_TYPE(self) == &PyBufferedWriter_Type &&
    1825           2 :                                 Py_TYPE(raw) == &PyFileIO_Type);
    1826             : 
    1827           2 :     self->ok = 1;
    1828           2 :     return 0;
    1829             : }
    1830             : 
    1831             : static Py_ssize_t
    1832           0 : _bufferedwriter_raw_write(buffered *self, char *start, Py_ssize_t len)
    1833             : {
    1834             :     Py_buffer buf;
    1835             :     PyObject *memobj, *res;
    1836             :     Py_ssize_t n;
    1837             :     int errnum;
    1838             :     /* NOTE: the buffer needn't be released as its object is NULL. */
    1839           0 :     if (PyBuffer_FillInfo(&buf, NULL, start, len, 1, PyBUF_CONTIG_RO) == -1)
    1840           0 :         return -1;
    1841           0 :     memobj = PyMemoryView_FromBuffer(&buf);
    1842           0 :     if (memobj == NULL)
    1843           0 :         return -1;
    1844             :     /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals() when EINTR
    1845             :        occurs so we needn't do it ourselves.
    1846             :        We then retry writing, ignoring the signal if no handler has
    1847             :        raised (see issue #10956).
    1848             :     */
    1849             :     do {
    1850           0 :         errno = 0;
    1851           0 :         res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_write, memobj, NULL);
    1852           0 :         errnum = errno;
    1853           0 :     } while (res == NULL && _PyIO_trap_eintr());
    1854           0 :     Py_DECREF(memobj);
    1855           0 :     if (res == NULL)
    1856           0 :         return -1;
    1857           0 :     if (res == Py_None) {
    1858             :         /* Non-blocking stream would have blocked. Special return code!
    1859             :            Being paranoid we reset errno in case it is changed by code
    1860             :            triggered by a decref.  errno is used by _set_BlockingIOError(). */
    1861           0 :         Py_DECREF(res);
    1862           0 :         errno = errnum;
    1863           0 :         return -2;
    1864             :     }
    1865           0 :     n = PyNumber_AsSsize_t(res, PyExc_ValueError);
    1866           0 :     Py_DECREF(res);
    1867           0 :     if (n < 0 || n > len) {
    1868           0 :         PyErr_Format(PyExc_IOError,
    1869             :                      "raw write() returned invalid length %zd "
    1870             :                      "(should have been between 0 and %zd)", n, len);
    1871           0 :         return -1;
    1872             :     }
    1873           0 :     if (n > 0 && self->abs_pos != -1)
    1874           0 :         self->abs_pos += n;
    1875           0 :     return n;
    1876             : }
    1877             : 
    1878             : /* `restore_pos` is 1 if we need to restore the raw stream position at
    1879             :    the end, 0 otherwise. */
    1880             : static PyObject *
    1881           0 : _bufferedwriter_flush_unlocked(buffered *self)
    1882             : {
    1883           0 :     Py_ssize_t written = 0;
    1884             :     Py_off_t n, rewind;
    1885             : 
    1886           0 :     if (!VALID_WRITE_BUFFER(self) || self->write_pos == self->write_end)
    1887             :         goto end;
    1888             :     /* First, rewind */
    1889           0 :     rewind = RAW_OFFSET(self) + (self->pos - self->write_pos);
    1890           0 :     if (rewind != 0) {
    1891           0 :         n = _buffered_raw_seek(self, -rewind, 1);
    1892           0 :         if (n < 0) {
    1893           0 :             goto error;
    1894             :         }
    1895           0 :         self->raw_pos -= rewind;
    1896             :     }
    1897           0 :     while (self->write_pos < self->write_end) {
    1898           0 :         n = _bufferedwriter_raw_write(self,
    1899           0 :             self->buffer + self->write_pos,
    1900           0 :             Py_SAFE_DOWNCAST(self->write_end - self->write_pos,
    1901             :                              Py_off_t, Py_ssize_t));
    1902           0 :         if (n == -1) {
    1903           0 :             goto error;
    1904             :         }
    1905           0 :         else if (n == -2) {
    1906           0 :             _set_BlockingIOError("write could not complete without blocking",
    1907             :                                  0);
    1908           0 :             goto error;
    1909             :         }
    1910           0 :         self->write_pos += n;
    1911           0 :         self->raw_pos = self->write_pos;
    1912           0 :         written += Py_SAFE_DOWNCAST(n, Py_off_t, Py_ssize_t);
    1913             :         /* Partial writes can return successfully when interrupted by a
    1914             :            signal (see write(2)).  We must run signal handlers before
    1915             :            blocking another time, possibly indefinitely. */
    1916           0 :         if (PyErr_CheckSignals() < 0)
    1917           0 :             goto error;
    1918             :     }
    1919             : 
    1920           0 :     _bufferedwriter_reset_buf(self);
    1921             : 
    1922             : end:
    1923           0 :     Py_RETURN_NONE;
    1924             : 
    1925             : error:
    1926           0 :     return NULL;
    1927             : }
    1928             : 
    1929             : static PyObject *
    1930           0 : bufferedwriter_write(buffered *self, PyObject *args)
    1931             : {
    1932           0 :     PyObject *res = NULL;
    1933             :     Py_buffer buf;
    1934             :     Py_ssize_t written, avail, remaining;
    1935             :     Py_off_t offset;
    1936             : 
    1937           0 :     CHECK_INITIALIZED(self)
    1938           0 :     if (!PyArg_ParseTuple(args, "y*:write", &buf)) {
    1939           0 :         return NULL;
    1940             :     }
    1941             : 
    1942           0 :     if (IS_CLOSED(self)) {
    1943           0 :         PyErr_SetString(PyExc_ValueError, "write to closed file");
    1944           0 :         PyBuffer_Release(&buf);
    1945           0 :         return NULL;
    1946             :     }
    1947             : 
    1948           0 :     if (!ENTER_BUFFERED(self)) {
    1949           0 :         PyBuffer_Release(&buf);
    1950           0 :         return NULL;
    1951             :     }
    1952             : 
    1953             :     /* Fast path: the data to write can be fully buffered. */
    1954           0 :     if (!VALID_READ_BUFFER(self) && !VALID_WRITE_BUFFER(self)) {
    1955           0 :         self->pos = 0;
    1956           0 :         self->raw_pos = 0;
    1957             :     }
    1958           0 :     avail = Py_SAFE_DOWNCAST(self->buffer_size - self->pos, Py_off_t, Py_ssize_t);
    1959           0 :     if (buf.len <= avail) {
    1960           0 :         memcpy(self->buffer + self->pos, buf.buf, buf.len);
    1961           0 :         if (!VALID_WRITE_BUFFER(self) || self->write_pos > self->pos) {
    1962           0 :             self->write_pos = self->pos;
    1963             :         }
    1964           0 :         ADJUST_POSITION(self, self->pos + buf.len);
    1965           0 :         if (self->pos > self->write_end)
    1966           0 :             self->write_end = self->pos;
    1967           0 :         written = buf.len;
    1968           0 :         goto end;
    1969             :     }
    1970             : 
    1971             :     /* First write the current buffer */
    1972           0 :     res = _bufferedwriter_flush_unlocked(self);
    1973           0 :     if (res == NULL) {
    1974           0 :         Py_ssize_t *w = _buffered_check_blocking_error();
    1975           0 :         if (w == NULL)
    1976           0 :             goto error;
    1977           0 :         if (self->readable)
    1978           0 :             _bufferedreader_reset_buf(self);
    1979             :         /* Make some place by shifting the buffer. */
    1980             :         assert(VALID_WRITE_BUFFER(self));
    1981           0 :         memmove(self->buffer, self->buffer + self->write_pos,
    1982           0 :                 Py_SAFE_DOWNCAST(self->write_end - self->write_pos,
    1983             :                                  Py_off_t, Py_ssize_t));
    1984           0 :         self->write_end -= self->write_pos;
    1985           0 :         self->raw_pos -= self->write_pos;
    1986           0 :         self->pos -= self->write_pos;
    1987           0 :         self->write_pos = 0;
    1988           0 :         avail = Py_SAFE_DOWNCAST(self->buffer_size - self->write_end,
    1989             :                                  Py_off_t, Py_ssize_t);
    1990           0 :         if (buf.len <= avail) {
    1991             :             /* Everything can be buffered */
    1992           0 :             PyErr_Clear();
    1993           0 :             memcpy(self->buffer + self->write_end, buf.buf, buf.len);
    1994           0 :             self->write_end += buf.len;
    1995           0 :             self->pos += buf.len;
    1996           0 :             written = buf.len;
    1997           0 :             goto end;
    1998             :         }
    1999             :         /* Buffer as much as possible. */
    2000           0 :         memcpy(self->buffer + self->write_end, buf.buf, avail);
    2001           0 :         self->write_end += avail;
    2002           0 :         self->pos += avail;
    2003             :         /* XXX Modifying the existing exception e using the pointer w
    2004             :            will change e.characters_written but not e.args[2].
    2005             :            Therefore we just replace with a new error. */
    2006           0 :         _set_BlockingIOError("write could not complete without blocking",
    2007             :                              avail);
    2008           0 :         goto error;
    2009             :     }
    2010           0 :     Py_CLEAR(res);
    2011             : 
    2012             :     /* Adjust the raw stream position if it is away from the logical stream
    2013             :        position. This happens if the read buffer has been filled but not
    2014             :        modified (and therefore _bufferedwriter_flush_unlocked() didn't rewind
    2015             :        the raw stream by itself).
    2016             :        Fixes issue #6629.
    2017             :     */
    2018           0 :     offset = RAW_OFFSET(self);
    2019           0 :     if (offset != 0) {
    2020           0 :         if (_buffered_raw_seek(self, -offset, 1) < 0)
    2021           0 :             goto error;
    2022           0 :         self->raw_pos -= offset;
    2023             :     }
    2024             : 
    2025             :     /* Then write buf itself. At this point the buffer has been emptied. */
    2026           0 :     remaining = buf.len;
    2027           0 :     written = 0;
    2028           0 :     while (remaining > self->buffer_size) {
    2029           0 :         Py_ssize_t n = _bufferedwriter_raw_write(
    2030           0 :             self, (char *) buf.buf + written, buf.len - written);
    2031           0 :         if (n == -1) {
    2032           0 :             goto error;
    2033           0 :         } else if (n == -2) {
    2034             :             /* Write failed because raw file is non-blocking */
    2035           0 :             if (remaining > self->buffer_size) {
    2036             :                 /* Can't buffer everything, still buffer as much as possible */
    2037           0 :                 memcpy(self->buffer,
    2038           0 :                        (char *) buf.buf + written, self->buffer_size);
    2039           0 :                 self->raw_pos = 0;
    2040           0 :                 ADJUST_POSITION(self, self->buffer_size);
    2041           0 :                 self->write_end = self->buffer_size;
    2042           0 :                 written += self->buffer_size;
    2043           0 :                 _set_BlockingIOError("write could not complete without "
    2044             :                                      "blocking", written);
    2045           0 :                 goto error;
    2046             :             }
    2047           0 :             PyErr_Clear();
    2048           0 :             break;
    2049             :         }
    2050           0 :         written += n;
    2051           0 :         remaining -= n;
    2052             :         /* Partial writes can return successfully when interrupted by a
    2053             :            signal (see write(2)).  We must run signal handlers before
    2054             :            blocking another time, possibly indefinitely. */
    2055           0 :         if (PyErr_CheckSignals() < 0)
    2056           0 :             goto error;
    2057             :     }
    2058           0 :     if (self->readable)
    2059           0 :         _bufferedreader_reset_buf(self);
    2060           0 :     if (remaining > 0) {
    2061           0 :         memcpy(self->buffer, (char *) buf.buf + written, remaining);
    2062           0 :         written += remaining;
    2063             :     }
    2064           0 :     self->write_pos = 0;
    2065             :     /* TODO: sanity check (remaining >= 0) */
    2066           0 :     self->write_end = remaining;
    2067           0 :     ADJUST_POSITION(self, remaining);
    2068           0 :     self->raw_pos = 0;
    2069             : 
    2070             : end:
    2071           0 :     res = PyLong_FromSsize_t(written);
    2072             : 
    2073             : error:
    2074           0 :     LEAVE_BUFFERED(self)
    2075           0 :     PyBuffer_Release(&buf);
    2076           0 :     return res;
    2077             : }
    2078             : 
    2079             : static PyMethodDef bufferedwriter_methods[] = {
    2080             :     /* BufferedIOMixin methods */
    2081             :     {"close", (PyCFunction)buffered_close, METH_NOARGS},
    2082             :     {"detach", (PyCFunction)buffered_detach, METH_NOARGS},
    2083             :     {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS},
    2084             :     {"readable", (PyCFunction)buffered_readable, METH_NOARGS},
    2085             :     {"writable", (PyCFunction)buffered_writable, METH_NOARGS},
    2086             :     {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
    2087             :     {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
    2088             :     {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
    2089             :     {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
    2090             : 
    2091             :     {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS},
    2092             :     {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS},
    2093             :     {"flush", (PyCFunction)buffered_flush, METH_NOARGS},
    2094             :     {"seek", (PyCFunction)buffered_seek, METH_VARARGS},
    2095             :     {"tell", (PyCFunction)buffered_tell, METH_NOARGS},
    2096             :     {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS},
    2097             :     {NULL, NULL}
    2098             : };
    2099             : 
    2100             : static PyMemberDef bufferedwriter_members[] = {
    2101             :     {"raw", T_OBJECT, offsetof(buffered, raw), READONLY},
    2102             :     {NULL}
    2103             : };
    2104             : 
    2105             : static PyGetSetDef bufferedwriter_getset[] = {
    2106             :     {"closed", (getter)buffered_closed_get, NULL, NULL},
    2107             :     {"name", (getter)buffered_name_get, NULL, NULL},
    2108             :     {"mode", (getter)buffered_mode_get, NULL, NULL},
    2109             :     {NULL}
    2110             : };
    2111             : 
    2112             : 
    2113             : PyTypeObject PyBufferedWriter_Type = {
    2114             :     PyVarObject_HEAD_INIT(NULL, 0)
    2115             :     "_io.BufferedWriter",       /*tp_name*/
    2116             :     sizeof(buffered),           /*tp_basicsize*/
    2117             :     0,                          /*tp_itemsize*/
    2118             :     (destructor)buffered_dealloc,     /*tp_dealloc*/
    2119             :     0,                          /*tp_print*/
    2120             :     0,                          /*tp_getattr*/
    2121             :     0,                          /*tp_setattr*/
    2122             :     0,                          /*tp_compare */
    2123             :     (reprfunc)buffered_repr,    /*tp_repr*/
    2124             :     0,                          /*tp_as_number*/
    2125             :     0,                          /*tp_as_sequence*/
    2126             :     0,                          /*tp_as_mapping*/
    2127             :     0,                          /*tp_hash */
    2128             :     0,                          /*tp_call*/
    2129             :     0,                          /*tp_str*/
    2130             :     0,                          /*tp_getattro*/
    2131             :     0,                          /*tp_setattro*/
    2132             :     0,                          /*tp_as_buffer*/
    2133             :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
    2134             :         | Py_TPFLAGS_HAVE_GC,   /*tp_flags*/
    2135             :     bufferedwriter_doc,         /* tp_doc */
    2136             :     (traverseproc)buffered_traverse, /* tp_traverse */
    2137             :     (inquiry)buffered_clear,    /* tp_clear */
    2138             :     0,                          /* tp_richcompare */
    2139             :     offsetof(buffered, weakreflist), /*tp_weaklistoffset*/
    2140             :     0,                          /* tp_iter */
    2141             :     0,                          /* tp_iternext */
    2142             :     bufferedwriter_methods,     /* tp_methods */
    2143             :     bufferedwriter_members,     /* tp_members */
    2144             :     bufferedwriter_getset,      /* tp_getset */
    2145             :     0,                          /* tp_base */
    2146             :     0,                          /* tp_dict */
    2147             :     0,                          /* tp_descr_get */
    2148             :     0,                          /* tp_descr_set */
    2149             :     offsetof(buffered, dict),   /* tp_dictoffset */
    2150             :     (initproc)bufferedwriter_init, /* tp_init */
    2151             :     0,                          /* tp_alloc */
    2152             :     PyType_GenericNew,          /* tp_new */
    2153             : };
    2154             : 
    2155             : 
    2156             : 
    2157             : /*
    2158             :  * BufferedRWPair
    2159             :  */
    2160             : 
    2161             : PyDoc_STRVAR(bufferedrwpair_doc,
    2162             :     "A buffered reader and writer object together.\n"
    2163             :     "\n"
    2164             :     "A buffered reader object and buffered writer object put together to\n"
    2165             :     "form a sequential IO object that can read and write. This is typically\n"
    2166             :     "used with a socket or two-way pipe.\n"
    2167             :     "\n"
    2168             :     "reader and writer are RawIOBase objects that are readable and\n"
    2169             :     "writeable respectively. If the buffer_size is omitted it defaults to\n"
    2170             :     "DEFAULT_BUFFER_SIZE.\n"
    2171             :     );
    2172             : 
    2173             : /* XXX The usefulness of this (compared to having two separate IO objects) is
    2174             :  * questionable.
    2175             :  */
    2176             : 
    2177             : typedef struct {
    2178             :     PyObject_HEAD
    2179             :     buffered *reader;
    2180             :     buffered *writer;
    2181             :     PyObject *dict;
    2182             :     PyObject *weakreflist;
    2183             : } rwpair;
    2184             : 
    2185             : static int
    2186           0 : bufferedrwpair_init(rwpair *self, PyObject *args, PyObject *kwds)
    2187             : {
    2188             :     PyObject *reader, *writer;
    2189           0 :     Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
    2190             : 
    2191           0 :     if (!PyArg_ParseTuple(args, "OO|n:BufferedRWPair", &reader, &writer,
    2192             :                           &buffer_size)) {
    2193           0 :         return -1;
    2194             :     }
    2195             : 
    2196           0 :     if (_PyIOBase_check_readable(reader, Py_True) == NULL)
    2197           0 :         return -1;
    2198           0 :     if (_PyIOBase_check_writable(writer, Py_True) == NULL)
    2199           0 :         return -1;
    2200             : 
    2201           0 :     self->reader = (buffered *) PyObject_CallFunction(
    2202             :             (PyObject *) &PyBufferedReader_Type, "On", reader, buffer_size);
    2203           0 :     if (self->reader == NULL)
    2204           0 :         return -1;
    2205             : 
    2206           0 :     self->writer = (buffered *) PyObject_CallFunction(
    2207             :             (PyObject *) &PyBufferedWriter_Type, "On", writer, buffer_size);
    2208           0 :     if (self->writer == NULL) {
    2209           0 :         Py_CLEAR(self->reader);
    2210           0 :         return -1;
    2211             :     }
    2212             : 
    2213           0 :     return 0;
    2214             : }
    2215             : 
    2216             : static int
    2217           0 : bufferedrwpair_traverse(rwpair *self, visitproc visit, void *arg)
    2218             : {
    2219           0 :     Py_VISIT(self->dict);
    2220           0 :     return 0;
    2221             : }
    2222             : 
    2223             : static int
    2224           0 : bufferedrwpair_clear(rwpair *self)
    2225             : {
    2226           0 :     Py_CLEAR(self->reader);
    2227           0 :     Py_CLEAR(self->writer);
    2228           0 :     Py_CLEAR(self->dict);
    2229           0 :     return 0;
    2230             : }
    2231             : 
    2232             : static void
    2233           0 : bufferedrwpair_dealloc(rwpair *self)
    2234             : {
    2235           0 :     _PyObject_GC_UNTRACK(self);
    2236           0 :     Py_CLEAR(self->reader);
    2237           0 :     Py_CLEAR(self->writer);
    2238           0 :     Py_CLEAR(self->dict);
    2239           0 :     Py_TYPE(self)->tp_free((PyObject *) self);
    2240           0 : }
    2241             : 
    2242             : static PyObject *
    2243           0 : _forward_call(buffered *self, _Py_Identifier *name, PyObject *args)
    2244             : {
    2245           0 :     PyObject *func = _PyObject_GetAttrId((PyObject *)self, name);
    2246             :     PyObject *ret;
    2247             : 
    2248           0 :     if (func == NULL) {
    2249           0 :         PyErr_SetString(PyExc_AttributeError, name->string);
    2250           0 :         return NULL;
    2251             :     }
    2252             : 
    2253           0 :     ret = PyObject_CallObject(func, args);
    2254           0 :     Py_DECREF(func);
    2255           0 :     return ret;
    2256             : }
    2257             : 
    2258             : static PyObject *
    2259           0 : bufferedrwpair_read(rwpair *self, PyObject *args)
    2260             : {
    2261           0 :     return _forward_call(self->reader, &PyId_read, args);
    2262             : }
    2263             : 
    2264             : static PyObject *
    2265           0 : bufferedrwpair_peek(rwpair *self, PyObject *args)
    2266             : {
    2267           0 :     return _forward_call(self->reader, &PyId_peek, args);
    2268             : }
    2269             : 
    2270             : static PyObject *
    2271           0 : bufferedrwpair_read1(rwpair *self, PyObject *args)
    2272             : {
    2273           0 :     return _forward_call(self->reader, &PyId_read1, args);
    2274             : }
    2275             : 
    2276             : static PyObject *
    2277           0 : bufferedrwpair_readinto(rwpair *self, PyObject *args)
    2278             : {
    2279           0 :     return _forward_call(self->reader, &PyId_readinto, args);
    2280             : }
    2281             : 
    2282             : static PyObject *
    2283           0 : bufferedrwpair_write(rwpair *self, PyObject *args)
    2284             : {
    2285           0 :     return _forward_call(self->writer, &PyId_write, args);
    2286             : }
    2287             : 
    2288             : static PyObject *
    2289           0 : bufferedrwpair_flush(rwpair *self, PyObject *args)
    2290             : {
    2291           0 :     return _forward_call(self->writer, &PyId_flush, args);
    2292             : }
    2293             : 
    2294             : static PyObject *
    2295           0 : bufferedrwpair_readable(rwpair *self, PyObject *args)
    2296             : {
    2297           0 :     return _forward_call(self->reader, &PyId_readable, args);
    2298             : }
    2299             : 
    2300             : static PyObject *
    2301           0 : bufferedrwpair_writable(rwpair *self, PyObject *args)
    2302             : {
    2303           0 :     return _forward_call(self->writer, &PyId_writable, args);
    2304             : }
    2305             : 
    2306             : static PyObject *
    2307           0 : bufferedrwpair_close(rwpair *self, PyObject *args)
    2308             : {
    2309           0 :     PyObject *ret = _forward_call(self->writer, &PyId_close, args);
    2310           0 :     if (ret == NULL)
    2311           0 :         return NULL;
    2312           0 :     Py_DECREF(ret);
    2313             : 
    2314           0 :     return _forward_call(self->reader, &PyId_close, args);
    2315             : }
    2316             : 
    2317             : static PyObject *
    2318           0 : bufferedrwpair_isatty(rwpair *self, PyObject *args)
    2319             : {
    2320           0 :     PyObject *ret = _forward_call(self->writer, &PyId_isatty, args);
    2321             : 
    2322           0 :     if (ret != Py_False) {
    2323             :         /* either True or exception */
    2324           0 :         return ret;
    2325             :     }
    2326           0 :     Py_DECREF(ret);
    2327             : 
    2328           0 :     return _forward_call(self->reader, &PyId_isatty, args);
    2329             : }
    2330             : 
    2331             : static PyObject *
    2332           0 : bufferedrwpair_closed_get(rwpair *self, void *context)
    2333             : {
    2334           0 :     if (self->writer == NULL) {
    2335           0 :         PyErr_SetString(PyExc_RuntimeError,
    2336             :                 "the BufferedRWPair object is being garbage-collected");
    2337           0 :         return NULL;
    2338             :     }
    2339           0 :     return PyObject_GetAttr((PyObject *) self->writer, _PyIO_str_closed);
    2340             : }
    2341             : 
    2342             : static PyMethodDef bufferedrwpair_methods[] = {
    2343             :     {"read", (PyCFunction)bufferedrwpair_read, METH_VARARGS},
    2344             :     {"peek", (PyCFunction)bufferedrwpair_peek, METH_VARARGS},
    2345             :     {"read1", (PyCFunction)bufferedrwpair_read1, METH_VARARGS},
    2346             :     {"readinto", (PyCFunction)bufferedrwpair_readinto, METH_VARARGS},
    2347             : 
    2348             :     {"write", (PyCFunction)bufferedrwpair_write, METH_VARARGS},
    2349             :     {"flush", (PyCFunction)bufferedrwpair_flush, METH_NOARGS},
    2350             : 
    2351             :     {"readable", (PyCFunction)bufferedrwpair_readable, METH_NOARGS},
    2352             :     {"writable", (PyCFunction)bufferedrwpair_writable, METH_NOARGS},
    2353             : 
    2354             :     {"close", (PyCFunction)bufferedrwpair_close, METH_NOARGS},
    2355             :     {"isatty", (PyCFunction)bufferedrwpair_isatty, METH_NOARGS},
    2356             : 
    2357             :     {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
    2358             : 
    2359             :     {NULL, NULL}
    2360             : };
    2361             : 
    2362             : static PyGetSetDef bufferedrwpair_getset[] = {
    2363             :     {"closed", (getter)bufferedrwpair_closed_get, NULL, NULL},
    2364             :     {NULL}
    2365             : };
    2366             : 
    2367             : PyTypeObject PyBufferedRWPair_Type = {
    2368             :     PyVarObject_HEAD_INIT(NULL, 0)
    2369             :     "_io.BufferedRWPair",       /*tp_name*/
    2370             :     sizeof(rwpair),            /*tp_basicsize*/
    2371             :     0,                          /*tp_itemsize*/
    2372             :     (destructor)bufferedrwpair_dealloc,     /*tp_dealloc*/
    2373             :     0,                          /*tp_print*/
    2374             :     0,                          /*tp_getattr*/
    2375             :     0,                          /*tp_setattr*/
    2376             :     0,                          /*tp_compare */
    2377             :     0,                          /*tp_repr*/
    2378             :     0,                          /*tp_as_number*/
    2379             :     0,                          /*tp_as_sequence*/
    2380             :     0,                          /*tp_as_mapping*/
    2381             :     0,                          /*tp_hash */
    2382             :     0,                          /*tp_call*/
    2383             :     0,                          /*tp_str*/
    2384             :     0,                          /*tp_getattro*/
    2385             :     0,                          /*tp_setattro*/
    2386             :     0,                          /*tp_as_buffer*/
    2387             :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
    2388             :         | Py_TPFLAGS_HAVE_GC,   /* tp_flags */
    2389             :     bufferedrwpair_doc,         /* tp_doc */
    2390             :     (traverseproc)bufferedrwpair_traverse, /* tp_traverse */
    2391             :     (inquiry)bufferedrwpair_clear, /* tp_clear */
    2392             :     0,                          /* tp_richcompare */
    2393             :     offsetof(rwpair, weakreflist), /*tp_weaklistoffset*/
    2394             :     0,                          /* tp_iter */
    2395             :     0,                          /* tp_iternext */
    2396             :     bufferedrwpair_methods,     /* tp_methods */
    2397             :     0,                          /* tp_members */
    2398             :     bufferedrwpair_getset,      /* tp_getset */
    2399             :     0,                          /* tp_base */
    2400             :     0,                          /* tp_dict */
    2401             :     0,                          /* tp_descr_get */
    2402             :     0,                          /* tp_descr_set */
    2403             :     offsetof(rwpair, dict),     /* tp_dictoffset */
    2404             :     (initproc)bufferedrwpair_init, /* tp_init */
    2405             :     0,                          /* tp_alloc */
    2406             :     PyType_GenericNew,          /* tp_new */
    2407             : };
    2408             : 
    2409             : 
    2410             : 
    2411             : /*
    2412             :  * BufferedRandom
    2413             :  */
    2414             : 
    2415             : PyDoc_STRVAR(bufferedrandom_doc,
    2416             :     "A buffered interface to random access streams.\n"
    2417             :     "\n"
    2418             :     "The constructor creates a reader and writer for a seekable stream,\n"
    2419             :     "raw, given in the first argument. If the buffer_size is omitted it\n"
    2420             :     "defaults to DEFAULT_BUFFER_SIZE.\n"
    2421             :     );
    2422             : 
    2423             : static int
    2424           0 : bufferedrandom_init(buffered *self, PyObject *args, PyObject *kwds)
    2425             : {
    2426           0 :     char *kwlist[] = {"raw", "buffer_size", NULL};
    2427           0 :     Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
    2428             :     PyObject *raw;
    2429             : 
    2430           0 :     self->ok = 0;
    2431           0 :     self->detached = 0;
    2432             : 
    2433           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedReader", kwlist,
    2434             :                                      &raw, &buffer_size)) {
    2435           0 :         return -1;
    2436             :     }
    2437             : 
    2438           0 :     if (_PyIOBase_check_seekable(raw, Py_True) == NULL)
    2439           0 :         return -1;
    2440           0 :     if (_PyIOBase_check_readable(raw, Py_True) == NULL)
    2441           0 :         return -1;
    2442           0 :     if (_PyIOBase_check_writable(raw, Py_True) == NULL)
    2443           0 :         return -1;
    2444             : 
    2445           0 :     Py_CLEAR(self->raw);
    2446           0 :     Py_INCREF(raw);
    2447           0 :     self->raw = raw;
    2448           0 :     self->buffer_size = buffer_size;
    2449           0 :     self->readable = 1;
    2450           0 :     self->writable = 1;
    2451             : 
    2452           0 :     if (_buffered_init(self) < 0)
    2453           0 :         return -1;
    2454           0 :     _bufferedreader_reset_buf(self);
    2455           0 :     _bufferedwriter_reset_buf(self);
    2456           0 :     self->pos = 0;
    2457             : 
    2458           0 :     self->fast_closed_checks = (Py_TYPE(self) == &PyBufferedRandom_Type &&
    2459           0 :                                 Py_TYPE(raw) == &PyFileIO_Type);
    2460             : 
    2461           0 :     self->ok = 1;
    2462           0 :     return 0;
    2463             : }
    2464             : 
    2465             : static PyMethodDef bufferedrandom_methods[] = {
    2466             :     /* BufferedIOMixin methods */
    2467             :     {"close", (PyCFunction)buffered_close, METH_NOARGS},
    2468             :     {"detach", (PyCFunction)buffered_detach, METH_NOARGS},
    2469             :     {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS},
    2470             :     {"readable", (PyCFunction)buffered_readable, METH_NOARGS},
    2471             :     {"writable", (PyCFunction)buffered_writable, METH_NOARGS},
    2472             :     {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
    2473             :     {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
    2474             :     {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
    2475             :     {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
    2476             : 
    2477             :     {"flush", (PyCFunction)buffered_flush, METH_NOARGS},
    2478             : 
    2479             :     {"seek", (PyCFunction)buffered_seek, METH_VARARGS},
    2480             :     {"tell", (PyCFunction)buffered_tell, METH_NOARGS},
    2481             :     {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS},
    2482             :     {"read", (PyCFunction)buffered_read, METH_VARARGS},
    2483             :     {"read1", (PyCFunction)buffered_read1, METH_VARARGS},
    2484             :     {"readinto", (PyCFunction)buffered_readinto, METH_VARARGS},
    2485             :     {"readline", (PyCFunction)buffered_readline, METH_VARARGS},
    2486             :     {"peek", (PyCFunction)buffered_peek, METH_VARARGS},
    2487             :     {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS},
    2488             :     {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS},
    2489             :     {NULL, NULL}
    2490             : };
    2491             : 
    2492             : static PyMemberDef bufferedrandom_members[] = {
    2493             :     {"raw", T_OBJECT, offsetof(buffered, raw), READONLY},
    2494             :     {NULL}
    2495             : };
    2496             : 
    2497             : static PyGetSetDef bufferedrandom_getset[] = {
    2498             :     {"closed", (getter)buffered_closed_get, NULL, NULL},
    2499             :     {"name", (getter)buffered_name_get, NULL, NULL},
    2500             :     {"mode", (getter)buffered_mode_get, NULL, NULL},
    2501             :     {NULL}
    2502             : };
    2503             : 
    2504             : 
    2505             : PyTypeObject PyBufferedRandom_Type = {
    2506             :     PyVarObject_HEAD_INIT(NULL, 0)
    2507             :     "_io.BufferedRandom",       /*tp_name*/
    2508             :     sizeof(buffered),           /*tp_basicsize*/
    2509             :     0,                          /*tp_itemsize*/
    2510             :     (destructor)buffered_dealloc,     /*tp_dealloc*/
    2511             :     0,                          /*tp_print*/
    2512             :     0,                          /*tp_getattr*/
    2513             :     0,                          /*tp_setattr*/
    2514             :     0,                          /*tp_compare */
    2515             :     (reprfunc)buffered_repr,    /*tp_repr*/
    2516             :     0,                          /*tp_as_number*/
    2517             :     0,                          /*tp_as_sequence*/
    2518             :     0,                          /*tp_as_mapping*/
    2519             :     0,                          /*tp_hash */
    2520             :     0,                          /*tp_call*/
    2521             :     0,                          /*tp_str*/
    2522             :     0,                          /*tp_getattro*/
    2523             :     0,                          /*tp_setattro*/
    2524             :     0,                          /*tp_as_buffer*/
    2525             :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
    2526             :         | Py_TPFLAGS_HAVE_GC,   /*tp_flags*/
    2527             :     bufferedrandom_doc,         /* tp_doc */
    2528             :     (traverseproc)buffered_traverse, /* tp_traverse */
    2529             :     (inquiry)buffered_clear,    /* tp_clear */
    2530             :     0,                          /* tp_richcompare */
    2531             :     offsetof(buffered, weakreflist), /*tp_weaklistoffset*/
    2532             :     0,                          /* tp_iter */
    2533             :     (iternextfunc)buffered_iternext, /* tp_iternext */
    2534             :     bufferedrandom_methods,     /* tp_methods */
    2535             :     bufferedrandom_members,     /* tp_members */
    2536             :     bufferedrandom_getset,      /* tp_getset */
    2537             :     0,                          /* tp_base */
    2538             :     0,                          /*tp_dict*/
    2539             :     0,                          /* tp_descr_get */
    2540             :     0,                          /* tp_descr_set */
    2541             :     offsetof(buffered, dict), /*tp_dictoffset*/
    2542             :     (initproc)bufferedrandom_init, /* tp_init */
    2543             :     0,                          /* tp_alloc */
    2544             :     PyType_GenericNew,          /* tp_new */
    2545             : };

Generated by: LCOV version 1.10