Index: Modules/_fileio.c =================================================================== --- Modules/_fileio.c (Revision 58929) +++ Modules/_fileio.c (Arbeitskopie) @@ -30,10 +30,11 @@ typedef struct { PyObject_HEAD int fd; + int closed : 1; unsigned readable : 1; unsigned writable : 1; int seekable : 2; /* -1 means unknown */ - int closefd : 1; + int close_fd : 1; PyObject *weakreflist; } PyFileIOObject; @@ -46,6 +47,12 @@ internal_close(PyFileIOObject *self) { int save_errno = 0; + + if (self->closed) { + return save_errno; + } + self->closed = 1; + if (self->fd >= 0) { int fd = self->fd; self->fd = -1; @@ -60,7 +67,7 @@ static PyObject * fileio_close(PyFileIOObject *self) { - if (!self->closefd) { + if (!self->close_fd) { if (PyErr_WarnEx(PyExc_RuntimeWarning, "Trying to close unclosable fd!", 3) < 0) { return NULL; @@ -86,6 +93,7 @@ self = (PyFileIOObject *) type->tp_alloc(type, 0); if (self != NULL) { self->fd = -1; + self->closed = 0; self->weakreflist = NULL; } @@ -127,7 +135,7 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) { PyFileIOObject *self = (PyFileIOObject *) oself; - static char *kwlist[] = {"file", "mode", "closefd", NULL}; + static char *kwlist[] = {"file", "mode", "close_fd", NULL}; char *name = NULL; char *mode = "r"; char *s; @@ -138,7 +146,7 @@ int rwa = 0, plus = 0, append = 0; int flags = 0; int fd = -1; - int closefd = 1; + int close_fd = 1; assert(PyFileIO_Check(oself)); if (self->fd >= 0) { @@ -148,7 +156,7 @@ } if (PyArg_ParseTupleAndKeywords(args, kwds, "i|si:fileio", - kwlist, &fd, &mode, &closefd)) { + kwlist, &fd, &mode, &close_fd)) { if (fd < 0) { PyErr_SetString(PyExc_ValueError, "Negative filedescriptor"); @@ -163,7 +171,7 @@ /* On NT, so wide API available */ PyObject *po; if (PyArg_ParseTupleAndKeywords(args, kwds, "U|si:fileio", - kwlist, &po, &mode, &closefd) + kwlist, &po, &mode, &close_fd) ) { widename = PyUnicode_AS_UNICODE(po); } else { @@ -178,7 +186,7 @@ if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:fileio", kwlist, Py_FileSystemDefaultEncoding, - &name, &mode, &closefd)) + &name, &mode, &close_fd)) goto error; } } @@ -247,13 +255,13 @@ if (fd >= 0) { self->fd = fd; - self->closefd = closefd; + self->close_fd = close_fd; } else { - self->closefd = 1; - if (!closefd) { + self->close_fd = 1; + if (!close_fd) { PyErr_SetString(PyExc_ValueError, - "Cannot use closefd=True with file name"); + "Cannot use close_fd=True with file name"); goto error; } @@ -292,7 +300,7 @@ if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); - if (self->fd >= 0 && self->closefd) { + if (self->fd >= 0 && self->close_fd) { errno = internal_close(self); if (errno < 0) { #ifdef HAVE_STRERROR @@ -315,12 +323,39 @@ } static PyObject * +err_invalid(void) +{ +#ifdef EBADF + errno = EBADF; + PyErr_SetFromErrno(PyExc_IOError); + return NULL; +#else + PyErr_SetString(PyExc_IOError, "Bad file descriptor"); + return NULL; +#endif +} + +static PyObject * err_mode(char *action) { PyErr_Format(PyExc_ValueError, "File not open for %s", action); return NULL; } +int +err_check(PyFileIOObject *self) +{ + if (self->closed) { + err_closed(); + return 1; + } + if (self->fd < 0) { + err_invalid(); + return 1; + } + return 0; +} + static PyObject * fileio_fileno(PyFileIOObject *self) { @@ -332,24 +367,24 @@ static PyObject * fileio_readable(PyFileIOObject *self) { - if (self->fd < 0) - return err_closed(); + if (err_check(self)) + return NULL; return PyBool_FromLong((long) self->readable); } static PyObject * fileio_writable(PyFileIOObject *self) { - if (self->fd < 0) - return err_closed(); + if (err_check(self)) + return NULL; return PyBool_FromLong((long) self->writable); } static PyObject * fileio_seekable(PyFileIOObject *self) { - if (self->fd < 0) - return err_closed(); + if (err_check(self)) + return NULL; if (self->seekable < 0) { int ret; Py_BEGIN_ALLOW_THREADS @@ -369,8 +404,8 @@ char *ptr; Py_ssize_t n; - if (self->fd < 0) - return err_closed(); + if (err_check(self)) + return NULL; if (!self->readable) return err_mode("reading"); @@ -456,8 +491,8 @@ Py_ssize_t size = -1; PyObject *bytes; - if (self->fd < 0) - return err_closed(); + if (err_check(self)) + return NULL; if (!self->readable) return err_mode("reading"); @@ -501,8 +536,8 @@ Py_ssize_t n; char *ptr; - if (self->fd < 0) - return err_closed(); + if (err_check(self)) + return NULL; if (!self->writable) return err_mode("writing"); @@ -593,8 +628,8 @@ PyObject *posobj; int whence = 0; - if (self->fd < 0) - return err_closed(); + if (err_check(self)) + return NULL; if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence)) return NULL; @@ -605,8 +640,8 @@ static PyObject * fileio_tell(PyFileIOObject *self, PyObject *args) { - if (self->fd < 0) - return err_closed(); + if (err_check(self)) + return NULL; return portable_lseek(self->fd, NULL, 1); } @@ -618,11 +653,9 @@ PyObject *posobj = NULL; Py_off_t pos; int ret; - int fd; - fd = self->fd; - if (fd < 0) - return err_closed(); + if (err_check(self)) + return NULL; if (!self->writable) return err_mode("writing"); @@ -630,7 +663,7 @@ return NULL; if (posobj == Py_None || posobj == NULL) { - posobj = portable_lseek(fd, NULL, 1); + posobj = portable_lseek(self->fd, NULL, 1); if (posobj == NULL) return NULL; } @@ -665,7 +698,7 @@ /* Have to move current pos to desired endpoint on Windows. */ errno = 0; - pos2 = portable_lseek(fd, posobj, SEEK_SET); + pos2 = portable_lseek(self->fd, posobj, SEEK_SET); if (pos2 == NULL) { Py_DECREF(posobj); Py_DECREF(oldposobj); @@ -676,7 +709,7 @@ /* Truncate. Note that this may grow the file! */ Py_BEGIN_ALLOW_THREADS errno = 0; - hFile = (HANDLE)_get_osfhandle(fd); + hFile = (HANDLE)_get_osfhandle(self->fd); ret = hFile == (HANDLE)-1; if (ret == 0) { ret = SetEndOfFile(hFile) == 0; @@ -687,7 +720,7 @@ if (ret == 0) { /* Move to the previous position in the file */ - pos2 = portable_lseek(fd, oldposobj, SEEK_SET); + pos2 = portable_lseek(self->fd, oldposobj, SEEK_SET); if (pos2 == NULL) { Py_DECREF(posobj); Py_DECREF(oldposobj); @@ -700,7 +733,7 @@ #else Py_BEGIN_ALLOW_THREADS errno = 0; - ret = ftruncate(fd, pos); + ret = ftruncate(self->fd, pos); Py_END_ALLOW_THREADS #endif /* !MS_WINDOWS */ @@ -742,8 +775,9 @@ { long res; - if (self->fd < 0) - return err_closed(); + if (err_check(self)) + return NULL; + Py_BEGIN_ALLOW_THREADS res = isatty(self->fd); Py_END_ALLOW_THREADS @@ -850,7 +884,7 @@ static PyObject * get_closed(PyFileIOObject *self, void *closure) { - return PyBool_FromLong((long)(self->fd < 0)); + return PyBool_FromLong((long)(self->closed)); } static PyObject * Index: Objects/fileobject.c =================================================================== --- Objects/fileobject.c (Revision 58929) +++ Objects/fileobject.c (Arbeitskopie) @@ -347,12 +347,20 @@ return (PyObject *) self; } +PyObject* +fileio_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyErr_SetString(PyExc_TypeError, + "cannot create 'stderrprinter' instances"); + return NULL; +} + PyObject * PyFile_NewStdPrinter(int fd) { PyStdPrinter_Object *self; - if ((fd != fileno(stdout) && fd != fileno(stderr)) || fd < 0) { + if (fd != fileno(stdout) && fd != fileno(stderr)) { /* not enough infrastructure for PyErr_BadInternalCall() */ return NULL; } @@ -372,14 +380,17 @@ Py_ssize_t n; if (self->fd < 0) { - PyErr_SetString(PyExc_ValueError, - "I/O operation on closed file"); - return NULL; + /* fd might be invalid on Windows + * I can't raise an exception here. It may lead to an + * unlimited recursion in the case stderr is invalid. + */ + return PyLong_FromLong((long)-1); } - if (!PyArg_ParseTuple(args, "s#", &c, &n)) { + if (!PyArg_ParseTuple(args, "s", &c)) { return NULL; } + n = strlen(c); Py_BEGIN_ALLOW_THREADS errno = 0; @@ -393,10 +404,24 @@ return NULL; } - return PyInt_FromSsize_t(n); + return PyLong_FromSsize_t(n); } +static PyObject * +stdprinter_fileno(PyStdPrinter_Object *self) +{ + return PyInt_FromLong((long) self->fd); +} + +static PyObject * +stdprinter_repr(PyStdPrinter_Object *self) +{ + return PyUnicode_FromFormat("", + self->fd, self); +} + static PyMethodDef stdprinter_methods[] = { + {"fileno", (PyCFunction)stdprinter_fileno, METH_NOARGS, ""}, {"write", (PyCFunction)stdprinter_write, METH_VARARGS, ""}, {NULL, NULL} /* sentinel */ }; @@ -412,7 +437,7 @@ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ - 0, /* tp_repr */ + (reprfunc)stdprinter_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ @@ -438,7 +463,7 @@ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - 0, /* tp_init */ + fileio_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ stdprinter_new, /* tp_new */ PyObject_Del, /* tp_free */