diff options
Diffstat (limited to 'Modules/_io/fileio.c')
| -rw-r--r-- | Modules/_io/fileio.c | 90 |
1 files changed, 77 insertions, 13 deletions
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 473919b..f96f2e2 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -2,9 +2,16 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" +#include "structmember.h" +#ifdef HAVE_SYS_TYPES_H #include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H #include <sys/stat.h> +#endif +#ifdef HAVE_FCNTL_H #include <fcntl.h> +#endif #include <stddef.h> /* For offsetof */ #include "_iomodule.h" @@ -49,6 +56,7 @@ typedef struct { unsigned int writable : 1; signed int seekable : 2; /* -1 means unknown */ unsigned int closefd : 1; + unsigned int deallocating: 1; PyObject *weakreflist; PyObject *dict; } fileio; @@ -63,6 +71,26 @@ _PyFileIO_closed(PyObject *self) return ((fileio *)self)->fd < 0; } +/* Because this can call arbitrary code, it shouldn't be called when + the refcount is 0 (that is, not directly from tp_dealloc unless + the refcount has been temporarily re-incremented). */ +static PyObject * +fileio_dealloc_warn(fileio *self, PyObject *source) +{ + if (self->fd >= 0 && self->closefd) { + PyObject *exc, *val, *tb; + PyErr_Fetch(&exc, &val, &tb); + if (PyErr_WarnFormat(PyExc_ResourceWarning, 1, + "unclosed file %R", source)) { + /* Spurious errors can appear at shutdown */ + if (PyErr_ExceptionMatches(PyExc_Warning)) + PyErr_WriteUnraisable((PyObject *) self); + } + PyErr_Restore(exc, val, tb); + } + Py_RETURN_NONE; +} + static PyObject * portable_lseek(int fd, PyObject *posobj, int whence); @@ -104,6 +132,13 @@ fileio_close(fileio *self) self->fd = -1; Py_RETURN_NONE; } + if (self->deallocating) { + PyObject *r = fileio_dealloc_warn(self, (PyObject *) self); + if (r) + Py_DECREF(r); + else + PyErr_Clear(); + } errno = internal_close(self); if (errno < 0) return NULL; @@ -224,11 +259,8 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) } #ifdef MS_WINDOWS - if (GetVersion() < 0x80000000) { - /* On NT, so wide API available */ - if (PyUnicode_Check(nameobj)) - widename = PyUnicode_AS_UNICODE(nameobj); - } + if (PyUnicode_Check(nameobj)) + widename = PyUnicode_AS_UNICODE(nameobj); if (widename == NULL) #endif if (fd < 0) @@ -244,8 +276,7 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) if (u == NULL) return -1; - stringobj = PyUnicode_AsEncodedString( - u, Py_FileSystemDefaultEncoding, "surrogateescape"); + stringobj = PyUnicode_EncodeFSDefault(u); Py_DECREF(u); if (stringobj == NULL) return -1; @@ -353,10 +384,15 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) PyErr_SetFromErrnoWithFilename(PyExc_IOError, name); goto error; } - if(dircheck(self, name) < 0) + if (dircheck(self, name) < 0) goto error; } +#if defined(MS_WINDOWS) || defined(__CYGWIN__) + /* don't translate newlines (\r\n <=> \n) */ + _setmode(self->fd, O_BINARY); +#endif + if (PyObject_SetAttrString((PyObject *)self, "name", nameobj) < 0) goto error; @@ -379,6 +415,8 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) error: ret = -1; + if (self->fd >= 0) + internal_close(self); done: Py_CLEAR(stringobj); @@ -402,6 +440,7 @@ fileio_clear(fileio *self) static void fileio_dealloc(fileio *self) { + self->deallocating = 1; if (_PyIOBase_finalize((PyObject *) self) < 0) return; _PyObject_GC_UNTRACK(self); @@ -421,7 +460,8 @@ err_closed(void) static PyObject * err_mode(char *action) { - PyErr_Format(PyExc_ValueError, "File not open for %s", action); + PyErr_Format(IO_STATE->unsupported_operation, + "File not open for %s", action); return NULL; } @@ -471,7 +511,7 @@ static PyObject * fileio_readinto(fileio *self, PyObject *args) { Py_buffer pbuf; - Py_ssize_t n; + Py_ssize_t n, len; if (self->fd < 0) return err_closed(); @@ -482,9 +522,16 @@ fileio_readinto(fileio *self, PyObject *args) return NULL; if (_PyVerify_fd(self->fd)) { + len = pbuf.len; Py_BEGIN_ALLOW_THREADS errno = 0; - n = read(self->fd, pbuf.buf, pbuf.len); +#if defined(MS_WIN64) || defined(MS_WINDOWS) + if (len > INT_MAX) + len = INT_MAX; + n = read(self->fd, pbuf.buf, (int)len); +#else + n = read(self->fd, pbuf.buf, len); +#endif Py_END_ALLOW_THREADS } else n = -1; @@ -650,7 +697,7 @@ static PyObject * fileio_write(fileio *self, PyObject *args) { Py_buffer pbuf; - Py_ssize_t n; + Py_ssize_t n, len; if (self->fd < 0) return err_closed(); @@ -663,7 +710,14 @@ fileio_write(fileio *self, PyObject *args) if (_PyVerify_fd(self->fd)) { Py_BEGIN_ALLOW_THREADS errno = 0; - n = write(self->fd, pbuf.buf, pbuf.len); + len = pbuf.len; +#if defined(MS_WIN64) || defined(MS_WINDOWS) + if (len > INT_MAX) + len = INT_MAX; + n = write(self->fd, pbuf.buf, (int)len); +#else + n = write(self->fd, pbuf.buf, len); +#endif Py_END_ALLOW_THREADS } else n = -1; @@ -917,6 +971,14 @@ fileio_isatty(fileio *self) return PyBool_FromLong(res); } +static PyObject * +fileio_getstate(fileio *self) +{ + PyErr_Format(PyExc_TypeError, + "cannot serialize '%s' object", Py_TYPE(self)->tp_name); + return NULL; +} + PyDoc_STRVAR(fileio_doc, "file(name: str[, mode: str]) -> file IO object\n" @@ -1010,6 +1072,8 @@ static PyMethodDef fileio_methods[] = { {"writable", (PyCFunction)fileio_writable, METH_NOARGS, writable_doc}, {"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc}, {"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc}, + {"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL}, + {"__getstate__", (PyCFunction)fileio_getstate, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; |
