LCOV - code coverage report
Current view: top level - Modules/_io - bufferedio.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 0 954 0.0 %
Date: 2017-04-19 Functions: 0 72 0.0 %

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

Generated by: LCOV version 1.10