@@ -33,6 +33,7 @@ typedef struct {
3333 unsigned readable : 1 ;
3434 unsigned writable : 1 ;
3535 int seekable : 2 ; /* -1 means unknown */
36+ int closefd : 1 ;
3637 PyObject * weakreflist ;
3738} PyFileIOObject ;
3839
@@ -59,6 +60,13 @@ internal_close(PyFileIOObject *self)
5960static PyObject *
6061fileio_close (PyFileIOObject * self )
6162{
63+ if (!self -> closefd ) {
64+ if (PyErr_WarnEx (PyExc_RuntimeWarning ,
65+ "Trying to close unclosable fd!" , 3 ) < 0 ) {
66+ return NULL ;
67+ }
68+ Py_RETURN_NONE ;
69+ }
6270 errno = internal_close (self );
6371 if (errno < 0 ) {
6472 PyErr_SetFromErrno (PyExc_IOError );
@@ -119,7 +127,7 @@ static int
119127fileio_init (PyObject * oself , PyObject * args , PyObject * kwds )
120128{
121129 PyFileIOObject * self = (PyFileIOObject * ) oself ;
122- static char * kwlist [] = {"file" , "mode" , NULL };
130+ static char * kwlist [] = {"file" , "mode" , "closefd" , NULL };
123131 char * name = NULL ;
124132 char * mode = "r" ;
125133 char * s ;
@@ -130,6 +138,7 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
130138 int rwa = 0 , plus = 0 , append = 0 ;
131139 int flags = 0 ;
132140 int fd = -1 ;
141+ int closefd = 1 ;
133142
134143 assert (PyFileIO_Check (oself ));
135144 if (self -> fd >= 0 ) {
@@ -138,8 +147,8 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
138147 return -1 ;
139148 }
140149
141- if (PyArg_ParseTupleAndKeywords (args , kwds , "i|s :fileio" ,
142- kwlist , & fd , & mode )) {
150+ if (PyArg_ParseTupleAndKeywords (args , kwds , "i|si :fileio" ,
151+ kwlist , & fd , & mode , & closefd )) {
143152 if (fd < 0 ) {
144153 PyErr_SetString (PyExc_ValueError ,
145154 "Negative filedescriptor" );
@@ -153,22 +162,23 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
153162 if (GetVersion () < 0x80000000 ) {
154163 /* On NT, so wide API available */
155164 PyObject * po ;
156- if (PyArg_ParseTupleAndKeywords (args , kwds , "U|s:fileio" ,
157- kwlist , & po , & mode )) {
165+ if (PyArg_ParseTupleAndKeywords (args , kwds , "U|si:fileio" ,
166+ kwlist , & po , & mode , & closefd )
167+ ) {
158168 widename = PyUnicode_AS_UNICODE (po );
159169 } else {
160170 /* Drop the argument parsing error as narrow
161171 strings are also valid. */
162172 PyErr_Clear ();
163173 }
164174 }
165- if (widename == NULL )
175+ if (widename == NULL )
166176#endif
167177 {
168- if (!PyArg_ParseTupleAndKeywords (args , kwds , "et|s :fileio" ,
178+ if (!PyArg_ParseTupleAndKeywords (args , kwds , "et|si :fileio" ,
169179 kwlist ,
170180 Py_FileSystemDefaultEncoding ,
171- & name , & mode ))
181+ & name , & mode , & closefd ))
172182 goto error ;
173183 }
174184 }
@@ -237,8 +247,16 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
237247
238248 if (fd >= 0 ) {
239249 self -> fd = fd ;
250+ self -> closefd = closefd ;
240251 }
241252 else {
253+ self -> closefd = 1 ;
254+ if (!closefd ) {
255+ PyErr_SetString (PyExc_ValueError ,
256+ "Cannot use closefd=True with file name" );
257+ goto error ;
258+ }
259+
242260 Py_BEGIN_ALLOW_THREADS
243261 errno = 0 ;
244262#ifdef MS_WINDOWS
@@ -270,7 +288,7 @@ fileio_dealloc(PyFileIOObject *self)
270288 if (self -> weakreflist != NULL )
271289 PyObject_ClearWeakRefs ((PyObject * ) self );
272290
273- if (self -> fd >= 0 ) {
291+ if (self -> fd >= 0 && self -> closefd ) {
274292 errno = internal_close (self );
275293 if (errno < 0 ) {
276294#ifdef HAVE_STRERROR
0 commit comments