summaryrefslogtreecommitdiffstats
path: root/Modules/_io/fileio.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_io/fileio.c')
-rw-r--r--Modules/_io/fileio.c90
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 */
};