1 
2 /* Emulation of PyFile_Check() and PyFile_AsFile() for Python 3. */
3 
4 static PyObject *PyIOBase_TypeObj;
5 
init_file_emulator(void)6 static int init_file_emulator(void)
7 {
8     if (PyIOBase_TypeObj == NULL) {
9         PyObject *io = PyImport_ImportModule("_io");
10         if (io == NULL)
11             return -1;
12         PyIOBase_TypeObj = PyObject_GetAttrString(io, "_IOBase");
13         if (PyIOBase_TypeObj == NULL)
14             return -1;
15     }
16     return 0;
17 }
18 
19 
20 #define PyFile_Check(p)  PyObject_IsInstance(p, PyIOBase_TypeObj)
21 
22 
_close_file_capsule(PyObject * ob_capsule)23 static void _close_file_capsule(PyObject *ob_capsule)
24 {
25     FILE *f = (FILE *)PyCapsule_GetPointer(ob_capsule, "FILE");
26     if (f != NULL)
27         fclose(f);
28 }
29 
30 
PyFile_AsFile(PyObject * ob_file)31 static FILE *PyFile_AsFile(PyObject *ob_file)
32 {
33     PyObject *ob, *ob_capsule = NULL, *ob_mode = NULL;
34     FILE *f;
35     int fd;
36     const char *mode;
37 
38     ob = PyObject_CallMethod(ob_file, "flush", NULL);
39     if (ob == NULL)
40         goto fail;
41     Py_DECREF(ob);
42 
43     ob_capsule = PyObject_GetAttrString(ob_file, "__cffi_FILE");
44     if (ob_capsule == NULL) {
45         PyErr_Clear();
46 
47         fd = PyObject_AsFileDescriptor(ob_file);
48         if (fd < 0)
49             goto fail;
50 
51         ob_mode = PyObject_GetAttrString(ob_file, "mode");
52         if (ob_mode == NULL)
53             goto fail;
54         mode = PyText_AsUTF8(ob_mode);
55         if (mode == NULL)
56             goto fail;
57 
58         fd = dup(fd);
59         if (fd < 0) {
60             PyErr_SetFromErrno(PyExc_OSError);
61             goto fail;
62         }
63 
64         f = fdopen(fd, mode);
65         if (f == NULL) {
66             close(fd);
67             PyErr_SetFromErrno(PyExc_OSError);
68             goto fail;
69         }
70         setbuf(f, NULL);    /* non-buffered */
71         Py_DECREF(ob_mode);
72         ob_mode = NULL;
73 
74         ob_capsule = PyCapsule_New(f, "FILE", _close_file_capsule);
75         if (ob_capsule == NULL) {
76             fclose(f);
77             goto fail;
78         }
79 
80         if (PyObject_SetAttrString(ob_file, "__cffi_FILE", ob_capsule) < 0)
81             goto fail;
82     }
83     else {
84         f = PyCapsule_GetPointer(ob_capsule, "FILE");
85     }
86     Py_DECREF(ob_capsule);   /* assumes still at least one reference */
87     return f;
88 
89  fail:
90     Py_XDECREF(ob_mode);
91     Py_XDECREF(ob_capsule);
92     return NULL;
93 }
94