Branch data Line data Source code
1 : : /* Author: Daniel Stutzbach */
2 : :
3 : : #define PY_SSIZE_T_CLEAN
4 : : #include "Python.h"
5 : : #include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH
6 : : #include "pycore_object.h" // _PyObject_GC_UNTRACK()
7 : : #include "structmember.h" // PyMemberDef
8 : : #include <stdbool.h>
9 : : #ifdef HAVE_SYS_TYPES_H
10 : : #include <sys/types.h>
11 : : #endif
12 : : #ifdef HAVE_SYS_STAT_H
13 : : #include <sys/stat.h>
14 : : #endif
15 : : #ifdef HAVE_IO_H
16 : : #include <io.h>
17 : : #endif
18 : : #ifdef HAVE_FCNTL_H
19 : : #include <fcntl.h>
20 : : #endif
21 : : #include <stddef.h> /* For offsetof */
22 : : #include "_iomodule.h"
23 : :
24 : : /*
25 : : * Known likely problems:
26 : : *
27 : : * - Files larger then 2**32-1
28 : : * - Files with unicode filenames
29 : : * - Passing numbers greater than 2**32-1 when an integer is expected
30 : : * - Making it work on Windows and other oddball platforms
31 : : *
32 : : * To Do:
33 : : *
34 : : * - autoconfify header file inclusion
35 : : */
36 : :
37 : : #ifdef MS_WINDOWS
38 : : /* can simulate truncate with Win32 API functions; see file_truncate */
39 : : #define HAVE_FTRUNCATE
40 : : #ifndef WIN32_LEAN_AND_MEAN
41 : : #define WIN32_LEAN_AND_MEAN
42 : : #endif
43 : : #include <windows.h>
44 : : #endif
45 : :
46 : : #if BUFSIZ < (8*1024)
47 : : #define SMALLCHUNK (8*1024)
48 : : #elif (BUFSIZ >= (2 << 25))
49 : : #error "unreasonable BUFSIZ > 64 MiB defined"
50 : : #else
51 : : #define SMALLCHUNK BUFSIZ
52 : : #endif
53 : :
54 : : /*[clinic input]
55 : : module _io
56 : : class _io.FileIO "fileio *" "clinic_state()->PyFileIO_Type"
57 : : [clinic start generated code]*/
58 : : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ac25ec278f4d6703]*/
59 : :
60 : : typedef struct {
61 : : PyObject_HEAD
62 : : int fd;
63 : : unsigned int created : 1;
64 : : unsigned int readable : 1;
65 : : unsigned int writable : 1;
66 : : unsigned int appending : 1;
67 : : signed int seekable : 2; /* -1 means unknown */
68 : : unsigned int closefd : 1;
69 : : char finalizing;
70 : : unsigned int blksize;
71 : : PyObject *weakreflist;
72 : : PyObject *dict;
73 : : } fileio;
74 : :
75 : : #define PyFileIO_Check(state, op) (PyObject_TypeCheck((op), state->PyFileIO_Type))
76 : :
77 : : /* Forward declarations */
78 : : static PyObject* portable_lseek(fileio *self, PyObject *posobj, int whence, bool suppress_pipe_error);
79 : :
80 : : int
81 : 1233403 : _PyFileIO_closed(PyObject *self)
82 : : {
83 : 1233403 : return ((fileio *)self)->fd < 0;
84 : : }
85 : :
86 : : /* Because this can call arbitrary code, it shouldn't be called when
87 : : the refcount is 0 (that is, not directly from tp_dealloc unless
88 : : the refcount has been temporarily re-incremented). */
89 : : static PyObject *
90 : 75 : fileio_dealloc_warn(fileio *self, PyObject *source)
91 : : {
92 [ + - - + ]: 75 : if (self->fd >= 0 && self->closefd) {
93 : 0 : PyObject *exc = PyErr_GetRaisedException();
94 [ # # ]: 0 : if (PyErr_ResourceWarning(source, 1, "unclosed file %R", source)) {
95 : : /* Spurious errors can appear at shutdown */
96 [ # # ]: 0 : if (PyErr_ExceptionMatches(PyExc_Warning))
97 : 0 : PyErr_WriteUnraisable((PyObject *) self);
98 : : }
99 : 0 : PyErr_SetRaisedException(exc);
100 : : }
101 : 75 : Py_RETURN_NONE;
102 : : }
103 : :
104 : : /* Returns 0 on success, -1 with exception set on failure. */
105 : : static int
106 : 1424 : internal_close(fileio *self)
107 : : {
108 : 1424 : int err = 0;
109 : 1424 : int save_errno = 0;
110 [ + - ]: 1424 : if (self->fd >= 0) {
111 : 1424 : int fd = self->fd;
112 : 1424 : self->fd = -1;
113 : : /* fd is accessible and someone else may have closed it */
114 : 1424 : Py_BEGIN_ALLOW_THREADS
115 : : _Py_BEGIN_SUPPRESS_IPH
116 : 1424 : err = close(fd);
117 [ - + ]: 1424 : if (err < 0)
118 : 0 : save_errno = errno;
119 : : _Py_END_SUPPRESS_IPH
120 : 1424 : Py_END_ALLOW_THREADS
121 : : }
122 [ - + ]: 1424 : if (err < 0) {
123 : 0 : errno = save_errno;
124 : 0 : PyErr_SetFromErrno(PyExc_OSError);
125 : 0 : return -1;
126 : : }
127 : 1424 : return 0;
128 : : }
129 : :
130 : : /*[clinic input]
131 : : _io.FileIO.close
132 : :
133 : : Close the file.
134 : :
135 : : A closed file cannot be used for further I/O operations. close() may be
136 : : called more than once without error.
137 : : [clinic start generated code]*/
138 : :
139 : : static PyObject *
140 : 1500 : _io_FileIO_close_impl(fileio *self)
141 : : /*[clinic end generated code: output=7737a319ef3bad0b input=f35231760d54a522]*/
142 : : {
143 : : PyObject *res;
144 : : PyObject *exc;
145 : : int rc;
146 : 1500 : res = PyObject_CallMethodOneArg((PyObject*)&PyRawIOBase_Type,
147 : : &_Py_ID(close), (PyObject *)self);
148 [ + + ]: 1500 : if (!self->closefd) {
149 : 76 : self->fd = -1;
150 : 76 : return res;
151 : : }
152 [ - + ]: 1424 : if (res == NULL) {
153 : 0 : exc = PyErr_GetRaisedException();
154 : : }
155 [ - + ]: 1424 : if (self->finalizing) {
156 : 0 : PyObject *r = fileio_dealloc_warn(self, (PyObject *) self);
157 [ # # ]: 0 : if (r) {
158 : 0 : Py_DECREF(r);
159 : : }
160 : : else {
161 : 0 : PyErr_Clear();
162 : : }
163 : : }
164 : 1424 : rc = internal_close(self);
165 [ - + ]: 1424 : if (res == NULL) {
166 : 0 : _PyErr_ChainExceptions1(exc);
167 : : }
168 [ - + ]: 1424 : if (rc < 0) {
169 [ # # ]: 0 : Py_CLEAR(res);
170 : : }
171 : 1424 : return res;
172 : : }
173 : :
174 : : static PyObject *
175 : 1660 : fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
176 : : {
177 : : fileio *self;
178 : :
179 : : assert(type != NULL && type->tp_alloc != NULL);
180 : :
181 : 1660 : self = (fileio *) type->tp_alloc(type, 0);
182 [ + - ]: 1660 : if (self != NULL) {
183 : 1660 : self->fd = -1;
184 : 1660 : self->created = 0;
185 : 1660 : self->readable = 0;
186 : 1660 : self->writable = 0;
187 : 1660 : self->appending = 0;
188 : 1660 : self->seekable = -1;
189 : 1660 : self->blksize = 0;
190 : 1660 : self->closefd = 1;
191 : 1660 : self->weakreflist = NULL;
192 : : }
193 : :
194 : 1660 : return (PyObject *) self;
195 : : }
196 : :
197 : : #ifdef O_CLOEXEC
198 : : extern int _Py_open_cloexec_works;
199 : : #endif
200 : :
201 : : /*[clinic input]
202 : : _io.FileIO.__init__
203 : : file as nameobj: object
204 : : mode: str = "r"
205 : : closefd: bool = True
206 : : opener: object = None
207 : :
208 : : Open a file.
209 : :
210 : : The mode can be 'r' (default), 'w', 'x' or 'a' for reading,
211 : : writing, exclusive creation or appending. The file will be created if it
212 : : doesn't exist when opened for writing or appending; it will be truncated
213 : : when opened for writing. A FileExistsError will be raised if it already
214 : : exists when opened for creating. Opening a file for creating implies
215 : : writing so this mode behaves in a similar way to 'w'.Add a '+' to the mode
216 : : to allow simultaneous reading and writing. A custom opener can be used by
217 : : passing a callable as *opener*. The underlying file descriptor for the file
218 : : object is then obtained by calling opener with (*name*, *flags*).
219 : : *opener* must return an open file descriptor (passing os.open as *opener*
220 : : results in functionality similar to passing None).
221 : : [clinic start generated code]*/
222 : :
223 : : static int
224 : 1660 : _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode,
225 : : int closefd, PyObject *opener)
226 : : /*[clinic end generated code: output=23413f68e6484bbd input=588aac967e0ba74b]*/
227 : : {
228 : : #ifdef MS_WINDOWS
229 : : Py_UNICODE *widename = NULL;
230 : : #else
231 : 1660 : const char *name = NULL;
232 : : #endif
233 : 1660 : PyObject *stringobj = NULL;
234 : : const char *s;
235 : 1660 : int ret = 0;
236 : 1660 : int rwa = 0, plus = 0;
237 : 1660 : int flags = 0;
238 : 1660 : int fd = -1;
239 : 1660 : int fd_is_own = 0;
240 : : #ifdef O_CLOEXEC
241 : 1660 : int *atomic_flag_works = &_Py_open_cloexec_works;
242 : : #elif !defined(MS_WINDOWS)
243 : : int *atomic_flag_works = NULL;
244 : : #endif
245 : : struct _Py_stat_struct fdfstat;
246 : : int fstat_result;
247 : 1660 : int async_err = 0;
248 : :
249 : : #ifdef Py_DEBUG
250 : : _PyIO_State *state = find_io_state_by_def(Py_TYPE(self));
251 : : assert(PyFileIO_Check(state, self));
252 : : #endif
253 [ - + ]: 1660 : if (self->fd >= 0) {
254 [ # # ]: 0 : if (self->closefd) {
255 : : /* Have to close the existing file first. */
256 [ # # ]: 0 : if (internal_close(self) < 0)
257 : 0 : return -1;
258 : : }
259 : : else
260 : 0 : self->fd = -1;
261 : : }
262 : :
263 : 1660 : fd = _PyLong_AsInt(nameobj);
264 [ + + ]: 1660 : if (fd < 0) {
265 [ - + ]: 1425 : if (!PyErr_Occurred()) {
266 : 0 : PyErr_SetString(PyExc_ValueError,
267 : : "negative file descriptor");
268 : 0 : return -1;
269 : : }
270 : 1425 : PyErr_Clear();
271 : : }
272 : :
273 [ + + ]: 1660 : if (fd < 0) {
274 : : #ifdef MS_WINDOWS
275 : : if (!PyUnicode_FSDecoder(nameobj, &stringobj)) {
276 : : return -1;
277 : : }
278 : : widename = PyUnicode_AsWideCharString(stringobj, NULL);
279 : : if (widename == NULL)
280 : : return -1;
281 : : #else
282 [ - + ]: 1425 : if (!PyUnicode_FSConverter(nameobj, &stringobj)) {
283 : 0 : return -1;
284 : : }
285 : 1425 : name = PyBytes_AS_STRING(stringobj);
286 : : #endif
287 : : }
288 : :
289 : 1660 : s = mode;
290 [ + + ]: 3479 : while (*s) {
291 [ - + + - : 1819 : switch (*s++) {
+ - - ]
292 : 0 : case 'x':
293 [ # # ]: 0 : if (rwa) {
294 : 0 : bad_mode:
295 : 0 : PyErr_SetString(PyExc_ValueError,
296 : : "Must have exactly one of create/read/write/append "
297 : : "mode and at most one plus");
298 : 0 : goto error;
299 : : }
300 : 0 : rwa = 1;
301 : 0 : self->created = 1;
302 : 0 : self->writable = 1;
303 : 0 : flags |= O_EXCL | O_CREAT;
304 : 0 : break;
305 : 1427 : case 'r':
306 [ - + ]: 1427 : if (rwa)
307 : 0 : goto bad_mode;
308 : 1427 : rwa = 1;
309 : 1427 : self->readable = 1;
310 : 1427 : break;
311 : 233 : case 'w':
312 [ - + ]: 233 : if (rwa)
313 : 0 : goto bad_mode;
314 : 233 : rwa = 1;
315 : 233 : self->writable = 1;
316 : 233 : flags |= O_CREAT | O_TRUNC;
317 : 233 : break;
318 : 0 : case 'a':
319 [ # # ]: 0 : if (rwa)
320 : 0 : goto bad_mode;
321 : 0 : rwa = 1;
322 : 0 : self->writable = 1;
323 : 0 : self->appending = 1;
324 : 0 : flags |= O_APPEND | O_CREAT;
325 : 0 : break;
326 : 159 : case 'b':
327 : 159 : break;
328 : 0 : case '+':
329 [ # # ]: 0 : if (plus)
330 : 0 : goto bad_mode;
331 : 0 : self->readable = self->writable = 1;
332 : 0 : plus = 1;
333 : 0 : break;
334 : 0 : default:
335 : 0 : PyErr_Format(PyExc_ValueError,
336 : : "invalid mode: %.200s", mode);
337 : 0 : goto error;
338 : : }
339 : : }
340 : :
341 [ - + ]: 1660 : if (!rwa)
342 : 0 : goto bad_mode;
343 : :
344 [ + + - + ]: 1660 : if (self->readable && self->writable)
345 : 0 : flags |= O_RDWR;
346 [ + + ]: 1660 : else if (self->readable)
347 : 1427 : flags |= O_RDONLY;
348 : : else
349 : 233 : flags |= O_WRONLY;
350 : :
351 : : #ifdef O_BINARY
352 : : flags |= O_BINARY;
353 : : #endif
354 : :
355 : : #ifdef MS_WINDOWS
356 : : flags |= O_NOINHERIT;
357 : : #elif defined(O_CLOEXEC)
358 : 1660 : flags |= O_CLOEXEC;
359 : : #endif
360 : :
361 [ - + ]: 1660 : if (PySys_Audit("open", "Osi", nameobj, mode, flags) < 0) {
362 : 0 : goto error;
363 : : }
364 : :
365 [ + + ]: 1660 : if (fd >= 0) {
366 : 235 : self->fd = fd;
367 : 235 : self->closefd = closefd;
368 : : }
369 : : else {
370 : 1425 : self->closefd = 1;
371 [ - + ]: 1425 : if (!closefd) {
372 : 0 : PyErr_SetString(PyExc_ValueError,
373 : : "Cannot use closefd=False with file name");
374 : 0 : goto error;
375 : : }
376 : :
377 : 1425 : errno = 0;
378 [ + - ]: 1425 : if (opener == Py_None) {
379 : : do {
380 : 1425 : Py_BEGIN_ALLOW_THREADS
381 : : #ifdef MS_WINDOWS
382 : : self->fd = _wopen(widename, flags, 0666);
383 : : #else
384 : 1425 : self->fd = open(name, flags, 0666);
385 : : #endif
386 : 1425 : Py_END_ALLOW_THREADS
387 [ - + - - ]: 160 : } while (self->fd < 0 && errno == EINTR &&
388 [ + + ]: 1425 : !(async_err = PyErr_CheckSignals()));
389 : :
390 [ - + ]: 1425 : if (async_err)
391 : 0 : goto error;
392 : : }
393 : : else {
394 : : PyObject *fdobj;
395 : :
396 : : #ifndef MS_WINDOWS
397 : : /* the opener may clear the atomic flag */
398 : 0 : atomic_flag_works = NULL;
399 : : #endif
400 : :
401 : 0 : fdobj = PyObject_CallFunction(opener, "Oi", nameobj, flags);
402 [ # # ]: 0 : if (fdobj == NULL)
403 : 0 : goto error;
404 [ # # ]: 0 : if (!PyLong_Check(fdobj)) {
405 : 0 : Py_DECREF(fdobj);
406 : 0 : PyErr_SetString(PyExc_TypeError,
407 : : "expected integer from opener");
408 : 0 : goto error;
409 : : }
410 : :
411 : 0 : self->fd = _PyLong_AsInt(fdobj);
412 : 0 : Py_DECREF(fdobj);
413 [ # # ]: 0 : if (self->fd < 0) {
414 [ # # ]: 0 : if (!PyErr_Occurred()) {
415 : : /* The opener returned a negative but didn't set an
416 : : exception. See issue #27066 */
417 : 0 : PyErr_Format(PyExc_ValueError,
418 : : "opener returned %d", self->fd);
419 : : }
420 : 0 : goto error;
421 : : }
422 : : }
423 : :
424 : 1425 : fd_is_own = 1;
425 [ + + ]: 1425 : if (self->fd < 0) {
426 : 160 : PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
427 : 160 : goto error;
428 : : }
429 : :
430 : : #ifndef MS_WINDOWS
431 [ - + ]: 1265 : if (_Py_set_inheritable(self->fd, 0, atomic_flag_works) < 0)
432 : 0 : goto error;
433 : : #endif
434 : : }
435 : :
436 : 1500 : self->blksize = DEFAULT_BUFFER_SIZE;
437 : 1500 : Py_BEGIN_ALLOW_THREADS
438 : 1500 : fstat_result = _Py_fstat_noraise(self->fd, &fdfstat);
439 : 1500 : Py_END_ALLOW_THREADS
440 [ - + ]: 1500 : if (fstat_result < 0) {
441 : : /* Tolerate fstat() errors other than EBADF. See Issue #25717, where
442 : : an anonymous file on a Virtual Box shared folder filesystem would
443 : : raise ENOENT. */
444 : : #ifdef MS_WINDOWS
445 : : if (GetLastError() == ERROR_INVALID_HANDLE) {
446 : : PyErr_SetFromWindowsErr(0);
447 : : #else
448 [ # # ]: 0 : if (errno == EBADF) {
449 : 0 : PyErr_SetFromErrno(PyExc_OSError);
450 : : #endif
451 : 0 : goto error;
452 : : }
453 : : }
454 : : else {
455 : : #if defined(S_ISDIR) && defined(EISDIR)
456 : : /* On Unix, open will succeed for directories.
457 : : In Python, there should be no file objects referring to
458 : : directories, so we need a check. */
459 [ - + ]: 1500 : if (S_ISDIR(fdfstat.st_mode)) {
460 : 0 : errno = EISDIR;
461 : 0 : PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
462 : 0 : goto error;
463 : : }
464 : : #endif /* defined(S_ISDIR) */
465 : : #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
466 [ + - ]: 1500 : if (fdfstat.st_blksize > 1)
467 : 1500 : self->blksize = fdfstat.st_blksize;
468 : : #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
469 : : }
470 : :
471 : : #if defined(MS_WINDOWS) || defined(__CYGWIN__)
472 : : /* don't translate newlines (\r\n <=> \n) */
473 : : _setmode(self->fd, O_BINARY);
474 : : #endif
475 : :
476 [ - + ]: 1500 : if (PyObject_SetAttr((PyObject *)self, &_Py_ID(name), nameobj) < 0)
477 : 0 : goto error;
478 : :
479 [ - + ]: 1500 : if (self->appending) {
480 : : /* For consistent behaviour, we explicitly seek to the
481 : : end of file (otherwise, it might be done only on the
482 : : first write()). */
483 : 0 : PyObject *pos = portable_lseek(self, NULL, 2, true);
484 [ # # ]: 0 : if (pos == NULL)
485 : 0 : goto error;
486 : 0 : Py_DECREF(pos);
487 : : }
488 : :
489 : 1500 : goto done;
490 : :
491 : 160 : error:
492 : 160 : ret = -1;
493 [ - + ]: 160 : if (!fd_is_own)
494 : 0 : self->fd = -1;
495 [ + - ]: 160 : if (self->fd >= 0) {
496 : 0 : PyObject *exc = PyErr_GetRaisedException();
497 : 0 : internal_close(self);
498 : 0 : _PyErr_ChainExceptions1(exc);
499 : : }
500 : :
501 : 160 : done:
502 : : #ifdef MS_WINDOWS
503 : : PyMem_Free(widename);
504 : : #endif
505 [ + + ]: 1660 : Py_CLEAR(stringobj);
506 : 1660 : return ret;
507 : : }
508 : :
509 : : static int
510 : 636 : fileio_traverse(fileio *self, visitproc visit, void *arg)
511 : : {
512 [ + - - + ]: 636 : Py_VISIT(Py_TYPE(self));
513 [ + - - + ]: 636 : Py_VISIT(self->dict);
514 : 636 : return 0;
515 : : }
516 : :
517 : : static int
518 : 0 : fileio_clear(fileio *self)
519 : : {
520 [ # # ]: 0 : Py_CLEAR(self->dict);
521 : 0 : return 0;
522 : : }
523 : :
524 : : static void
525 : 1660 : fileio_dealloc(fileio *self)
526 : : {
527 : 1660 : PyTypeObject *tp = Py_TYPE(self);
528 : 1660 : self->finalizing = 1;
529 [ - + ]: 1660 : if (_PyIOBase_finalize((PyObject *) self) < 0)
530 : 0 : return;
531 : 1660 : _PyObject_GC_UNTRACK(self);
532 [ - + ]: 1660 : if (self->weakreflist != NULL)
533 : 0 : PyObject_ClearWeakRefs((PyObject *) self);
534 [ + + ]: 1660 : Py_CLEAR(self->dict);
535 : 1660 : tp->tp_free((PyObject *)self);
536 : 1660 : Py_DECREF(tp);
537 : : }
538 : :
539 : : static PyObject *
540 : 0 : err_closed(void)
541 : : {
542 : 0 : PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
543 : 0 : return NULL;
544 : : }
545 : :
546 : : static PyObject *
547 : 0 : err_mode(const char *action)
548 : : {
549 : 0 : _PyIO_State *state = IO_STATE();
550 [ # # ]: 0 : if (state != NULL)
551 : 0 : PyErr_Format(state->unsupported_operation,
552 : : "File not open for %s", action);
553 : 0 : return NULL;
554 : : }
555 : :
556 : : /*[clinic input]
557 : : _io.FileIO.fileno
558 : :
559 : : Return the underlying file descriptor (an integer).
560 : : [clinic start generated code]*/
561 : :
562 : : static PyObject *
563 : 13 : _io_FileIO_fileno_impl(fileio *self)
564 : : /*[clinic end generated code: output=a9626ce5398ece90 input=0b9b2de67335ada3]*/
565 : : {
566 [ - + ]: 13 : if (self->fd < 0)
567 : 0 : return err_closed();
568 : 13 : return PyLong_FromLong((long) self->fd);
569 : : }
570 : :
571 : : /*[clinic input]
572 : : _io.FileIO.readable
573 : :
574 : : True if file was opened in a read mode.
575 : : [clinic start generated code]*/
576 : :
577 : : static PyObject *
578 : 1946 : _io_FileIO_readable_impl(fileio *self)
579 : : /*[clinic end generated code: output=640744a6150fe9ba input=a3fdfed6eea721c5]*/
580 : : {
581 [ - + ]: 1946 : if (self->fd < 0)
582 : 0 : return err_closed();
583 : 1946 : return PyBool_FromLong((long) self->readable);
584 : : }
585 : :
586 : : /*[clinic input]
587 : : _io.FileIO.writable
588 : :
589 : : True if file was opened in a write mode.
590 : : [clinic start generated code]*/
591 : :
592 : : static PyObject *
593 : 148 : _io_FileIO_writable_impl(fileio *self)
594 : : /*[clinic end generated code: output=96cefc5446e89977 input=c204a808ca2e1748]*/
595 : : {
596 [ - + ]: 148 : if (self->fd < 0)
597 : 0 : return err_closed();
598 : 148 : return PyBool_FromLong((long) self->writable);
599 : : }
600 : :
601 : : /*[clinic input]
602 : : _io.FileIO.seekable
603 : :
604 : : True if file supports random-access.
605 : : [clinic start generated code]*/
606 : :
607 : : static PyObject *
608 : 842 : _io_FileIO_seekable_impl(fileio *self)
609 : : /*[clinic end generated code: output=47909ca0a42e9287 input=c8e5554d2fd63c7f]*/
610 : : {
611 [ - + ]: 842 : if (self->fd < 0)
612 : 0 : return err_closed();
613 [ - + ]: 842 : if (self->seekable < 0) {
614 : : /* portable_lseek() sets the seekable attribute */
615 : 0 : PyObject *pos = portable_lseek(self, NULL, SEEK_CUR, false);
616 : : assert(self->seekable >= 0);
617 [ # # ]: 0 : if (pos == NULL) {
618 : 0 : PyErr_Clear();
619 : : }
620 : : else {
621 : 0 : Py_DECREF(pos);
622 : : }
623 : : }
624 : 842 : return PyBool_FromLong((long) self->seekable);
625 : : }
626 : :
627 : : /*[clinic input]
628 : : _io.FileIO.readinto
629 : : buffer: Py_buffer(accept={rwbuffer})
630 : : /
631 : :
632 : : Same as RawIOBase.readinto().
633 : : [clinic start generated code]*/
634 : :
635 : : static PyObject *
636 : 4092 : _io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer)
637 : : /*[clinic end generated code: output=b01a5a22c8415cb4 input=4721d7b68b154eaf]*/
638 : : {
639 : : Py_ssize_t n;
640 : : int err;
641 : :
642 [ - + ]: 4092 : if (self->fd < 0)
643 : 0 : return err_closed();
644 [ - + ]: 4092 : if (!self->readable)
645 : 0 : return err_mode("reading");
646 : :
647 : 4092 : n = _Py_read(self->fd, buffer->buf, buffer->len);
648 : : /* copy errno because PyBuffer_Release() can indirectly modify it */
649 : 4092 : err = errno;
650 : :
651 [ - + ]: 4092 : if (n == -1) {
652 [ # # ]: 0 : if (err == EAGAIN) {
653 : 0 : PyErr_Clear();
654 : 0 : Py_RETURN_NONE;
655 : : }
656 : 0 : return NULL;
657 : : }
658 : :
659 : 4092 : return PyLong_FromSsize_t(n);
660 : : }
661 : :
662 : : static size_t
663 : 0 : new_buffersize(fileio *self, size_t currentsize)
664 : : {
665 : : size_t addend;
666 : :
667 : : /* Expand the buffer by an amount proportional to the current size,
668 : : giving us amortized linear-time behavior. For bigger sizes, use a
669 : : less-than-double growth factor to avoid excessive allocation. */
670 : : assert(currentsize <= PY_SSIZE_T_MAX);
671 [ # # ]: 0 : if (currentsize > 65536)
672 : 0 : addend = currentsize >> 3;
673 : : else
674 : 0 : addend = 256 + currentsize;
675 [ # # ]: 0 : if (addend < SMALLCHUNK)
676 : : /* Avoid tiny read() calls. */
677 : 0 : addend = SMALLCHUNK;
678 : 0 : return addend + currentsize;
679 : : }
680 : :
681 : : /*[clinic input]
682 : : _io.FileIO.readall
683 : :
684 : : Read all data from the file, returned as bytes.
685 : :
686 : : In non-blocking mode, returns as much as is immediately available,
687 : : or None if no data is available. Return an empty bytes object at EOF.
688 : : [clinic start generated code]*/
689 : :
690 : : static PyObject *
691 : 612 : _io_FileIO_readall_impl(fileio *self)
692 : : /*[clinic end generated code: output=faa0292b213b4022 input=dbdc137f55602834]*/
693 : : {
694 : : struct _Py_stat_struct status;
695 : : Py_off_t pos, end;
696 : : PyObject *result;
697 : 612 : Py_ssize_t bytes_read = 0;
698 : : Py_ssize_t n;
699 : : size_t bufsize;
700 : : int fstat_result;
701 : :
702 [ - + ]: 612 : if (self->fd < 0)
703 : 0 : return err_closed();
704 : :
705 : 612 : Py_BEGIN_ALLOW_THREADS
706 : : _Py_BEGIN_SUPPRESS_IPH
707 : : #ifdef MS_WINDOWS
708 : : pos = _lseeki64(self->fd, 0L, SEEK_CUR);
709 : : #else
710 : 612 : pos = lseek(self->fd, 0L, SEEK_CUR);
711 : : #endif
712 : : _Py_END_SUPPRESS_IPH
713 : 612 : fstat_result = _Py_fstat_noraise(self->fd, &status);
714 : 612 : Py_END_ALLOW_THREADS
715 : :
716 [ + - ]: 612 : if (fstat_result == 0)
717 : 612 : end = status.st_size;
718 : : else
719 : 0 : end = (Py_off_t)-1;
720 : :
721 [ + + + - : 612 : if (end > 0 && end >= pos && pos >= 0 && end - pos < PY_SSIZE_T_MAX) {
+ - + - ]
722 : : /* This is probably a real file, so we try to allocate a
723 : : buffer one byte larger than the rest of the file. If the
724 : : calculation is right then we should get EOF without having
725 : : to enlarge the buffer. */
726 : 609 : bufsize = (size_t)(end - pos + 1);
727 : : } else {
728 : 3 : bufsize = SMALLCHUNK;
729 : : }
730 : :
731 : 612 : result = PyBytes_FromStringAndSize(NULL, bufsize);
732 [ - + ]: 612 : if (result == NULL)
733 : 0 : return NULL;
734 : :
735 : : while (1) {
736 [ - + ]: 1221 : if (bytes_read >= (Py_ssize_t)bufsize) {
737 : 0 : bufsize = new_buffersize(self, bytes_read);
738 [ # # # # ]: 0 : if (bufsize > PY_SSIZE_T_MAX || bufsize <= 0) {
739 : 0 : PyErr_SetString(PyExc_OverflowError,
740 : : "unbounded read returned more bytes "
741 : : "than a Python bytes object can hold");
742 : 0 : Py_DECREF(result);
743 : 0 : return NULL;
744 : : }
745 : :
746 [ # # ]: 0 : if (PyBytes_GET_SIZE(result) < (Py_ssize_t)bufsize) {
747 [ # # ]: 0 : if (_PyBytes_Resize(&result, bufsize) < 0)
748 : 0 : return NULL;
749 : : }
750 : : }
751 : :
752 : 2442 : n = _Py_read(self->fd,
753 : 1221 : PyBytes_AS_STRING(result) + bytes_read,
754 : : bufsize - bytes_read);
755 : :
756 [ + + ]: 1221 : if (n == 0)
757 : 612 : break;
758 [ - + ]: 609 : if (n == -1) {
759 [ # # ]: 0 : if (errno == EAGAIN) {
760 : 0 : PyErr_Clear();
761 [ # # ]: 0 : if (bytes_read > 0)
762 : 0 : break;
763 : 0 : Py_DECREF(result);
764 : 0 : Py_RETURN_NONE;
765 : : }
766 : 0 : Py_DECREF(result);
767 : 0 : return NULL;
768 : : }
769 : 609 : bytes_read += n;
770 : 609 : pos += n;
771 : : }
772 : :
773 [ + - ]: 612 : if (PyBytes_GET_SIZE(result) > bytes_read) {
774 [ - + ]: 612 : if (_PyBytes_Resize(&result, bytes_read) < 0)
775 : 0 : return NULL;
776 : : }
777 : 612 : return result;
778 : : }
779 : :
780 : : /*[clinic input]
781 : : _io.FileIO.read
782 : : size: Py_ssize_t(accept={int, NoneType}) = -1
783 : : /
784 : :
785 : : Read at most size bytes, returned as bytes.
786 : :
787 : : Only makes one system call, so less data may be returned than requested.
788 : : In non-blocking mode, returns None if no data is available.
789 : : Return an empty bytes object at EOF.
790 : : [clinic start generated code]*/
791 : :
792 : : static PyObject *
793 : 0 : _io_FileIO_read_impl(fileio *self, Py_ssize_t size)
794 : : /*[clinic end generated code: output=42528d39dd0ca641 input=bec9a2c704ddcbc9]*/
795 : : {
796 : : char *ptr;
797 : : Py_ssize_t n;
798 : : PyObject *bytes;
799 : :
800 [ # # ]: 0 : if (self->fd < 0)
801 : 0 : return err_closed();
802 [ # # ]: 0 : if (!self->readable)
803 : 0 : return err_mode("reading");
804 : :
805 [ # # ]: 0 : if (size < 0)
806 : 0 : return _io_FileIO_readall_impl(self);
807 : :
808 : : if (size > _PY_READ_MAX) {
809 : : size = _PY_READ_MAX;
810 : : }
811 : :
812 : 0 : bytes = PyBytes_FromStringAndSize(NULL, size);
813 [ # # ]: 0 : if (bytes == NULL)
814 : 0 : return NULL;
815 : 0 : ptr = PyBytes_AS_STRING(bytes);
816 : :
817 : 0 : n = _Py_read(self->fd, ptr, size);
818 [ # # ]: 0 : if (n == -1) {
819 : : /* copy errno because Py_DECREF() can indirectly modify it */
820 : 0 : int err = errno;
821 : 0 : Py_DECREF(bytes);
822 [ # # ]: 0 : if (err == EAGAIN) {
823 : 0 : PyErr_Clear();
824 : 0 : Py_RETURN_NONE;
825 : : }
826 : 0 : return NULL;
827 : : }
828 : :
829 [ # # ]: 0 : if (n != size) {
830 [ # # ]: 0 : if (_PyBytes_Resize(&bytes, n) < 0) {
831 [ # # ]: 0 : Py_CLEAR(bytes);
832 : 0 : return NULL;
833 : : }
834 : : }
835 : :
836 : 0 : return (PyObject *) bytes;
837 : : }
838 : :
839 : : /*[clinic input]
840 : : _io.FileIO.write
841 : : b: Py_buffer
842 : : /
843 : :
844 : : Write buffer b to file, return number of bytes written.
845 : :
846 : : Only makes one system call, so not all of the data may be written.
847 : : The number of bytes actually written is returned. In non-blocking mode,
848 : : returns None if the write would block.
849 : : [clinic start generated code]*/
850 : :
851 : : static PyObject *
852 : 919 : _io_FileIO_write_impl(fileio *self, Py_buffer *b)
853 : : /*[clinic end generated code: output=b4059db3d363a2f7 input=6e7908b36f0ce74f]*/
854 : : {
855 : : Py_ssize_t n;
856 : : int err;
857 : :
858 [ - + ]: 919 : if (self->fd < 0)
859 : 0 : return err_closed();
860 [ - + ]: 919 : if (!self->writable)
861 : 0 : return err_mode("writing");
862 : :
863 : 919 : n = _Py_write(self->fd, b->buf, b->len);
864 : : /* copy errno because PyBuffer_Release() can indirectly modify it */
865 : 919 : err = errno;
866 : :
867 [ - + ]: 919 : if (n < 0) {
868 [ # # ]: 0 : if (err == EAGAIN) {
869 : 0 : PyErr_Clear();
870 : 0 : Py_RETURN_NONE;
871 : : }
872 : 0 : return NULL;
873 : : }
874 : :
875 : 919 : return PyLong_FromSsize_t(n);
876 : : }
877 : :
878 : : /* XXX Windows support below is likely incomplete */
879 : :
880 : : /* Cribbed from posix_lseek() */
881 : : static PyObject *
882 : 1519 : portable_lseek(fileio *self, PyObject *posobj, int whence, bool suppress_pipe_error)
883 : : {
884 : : Py_off_t pos, res;
885 : 1519 : int fd = self->fd;
886 : :
887 : : #ifdef SEEK_SET
888 : : /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
889 : : switch (whence) {
890 : : #if SEEK_SET != 0
891 : : case 0: whence = SEEK_SET; break;
892 : : #endif
893 : : #if SEEK_CUR != 1
894 : : case 1: whence = SEEK_CUR; break;
895 : : #endif
896 : : #if SEEK_END != 2
897 : : case 2: whence = SEEK_END; break;
898 : : #endif
899 : : }
900 : : #endif /* SEEK_SET */
901 : :
902 [ + + ]: 1519 : if (posobj == NULL) {
903 : 1431 : pos = 0;
904 : : }
905 : : else {
906 : : #if defined(HAVE_LARGEFILE_SUPPORT)
907 : : pos = PyLong_AsLongLong(posobj);
908 : : #else
909 : 88 : pos = PyLong_AsLong(posobj);
910 : : #endif
911 [ - + ]: 88 : if (PyErr_Occurred())
912 : 0 : return NULL;
913 : : }
914 : :
915 : 1519 : Py_BEGIN_ALLOW_THREADS
916 : : _Py_BEGIN_SUPPRESS_IPH
917 : : #ifdef MS_WINDOWS
918 : : res = _lseeki64(fd, pos, whence);
919 : : #else
920 : 1519 : res = lseek(fd, pos, whence);
921 : : #endif
922 : : _Py_END_SUPPRESS_IPH
923 : 1519 : Py_END_ALLOW_THREADS
924 : :
925 [ + + ]: 1519 : if (self->seekable < 0) {
926 : 1341 : self->seekable = (res >= 0);
927 : : }
928 : :
929 [ + + ]: 1519 : if (res < 0) {
930 [ - + - - ]: 75 : if (suppress_pipe_error && errno == ESPIPE) {
931 : 0 : res = 0;
932 : : } else {
933 : 75 : return PyErr_SetFromErrno(PyExc_OSError);
934 : : }
935 : : }
936 : :
937 : : #if defined(HAVE_LARGEFILE_SUPPORT)
938 : : return PyLong_FromLongLong(res);
939 : : #else
940 : 1444 : return PyLong_FromLong(res);
941 : : #endif
942 : : }
943 : :
944 : : /*[clinic input]
945 : : _io.FileIO.seek
946 : : pos: object
947 : : whence: int = 0
948 : : /
949 : :
950 : : Move to new file position and return the file position.
951 : :
952 : : Argument offset is a byte count. Optional argument whence defaults to
953 : : SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values
954 : : are SEEK_CUR or 1 (move relative to current position, positive or negative),
955 : : and SEEK_END or 2 (move relative to end of file, usually negative, although
956 : : many platforms allow seeking beyond the end of a file).
957 : :
958 : : Note that not all file objects are seekable.
959 : : [clinic start generated code]*/
960 : :
961 : : static PyObject *
962 : 88 : _io_FileIO_seek_impl(fileio *self, PyObject *pos, int whence)
963 : : /*[clinic end generated code: output=c976acdf054e6655 input=0439194b0774d454]*/
964 : : {
965 [ - + ]: 88 : if (self->fd < 0)
966 : 0 : return err_closed();
967 : :
968 : 88 : return portable_lseek(self, pos, whence, false);
969 : : }
970 : :
971 : : /*[clinic input]
972 : : _io.FileIO.tell
973 : :
974 : : Current file position.
975 : :
976 : : Can raise OSError for non seekable files.
977 : : [clinic start generated code]*/
978 : :
979 : : static PyObject *
980 : 1431 : _io_FileIO_tell_impl(fileio *self)
981 : : /*[clinic end generated code: output=ffe2147058809d0b input=807e24ead4cec2f9]*/
982 : : {
983 [ - + ]: 1431 : if (self->fd < 0)
984 : 0 : return err_closed();
985 : :
986 : 1431 : return portable_lseek(self, NULL, 1, false);
987 : : }
988 : :
989 : : #ifdef HAVE_FTRUNCATE
990 : : /*[clinic input]
991 : : _io.FileIO.truncate
992 : : size as posobj: object = None
993 : : /
994 : :
995 : : Truncate the file to at most size bytes and return the truncated size.
996 : :
997 : : Size defaults to the current file position, as returned by tell().
998 : : The current file position is changed to the value of size.
999 : : [clinic start generated code]*/
1000 : :
1001 : : static PyObject *
1002 : 0 : _io_FileIO_truncate_impl(fileio *self, PyObject *posobj)
1003 : : /*[clinic end generated code: output=e49ca7a916c176fa input=b0ac133939823875]*/
1004 : : {
1005 : : Py_off_t pos;
1006 : : int ret;
1007 : : int fd;
1008 : :
1009 : 0 : fd = self->fd;
1010 [ # # ]: 0 : if (fd < 0)
1011 : 0 : return err_closed();
1012 [ # # ]: 0 : if (!self->writable)
1013 : 0 : return err_mode("writing");
1014 : :
1015 [ # # ]: 0 : if (posobj == Py_None) {
1016 : : /* Get the current position. */
1017 : 0 : posobj = portable_lseek(self, NULL, 1, false);
1018 [ # # ]: 0 : if (posobj == NULL)
1019 : 0 : return NULL;
1020 : : }
1021 : : else {
1022 : 0 : Py_INCREF(posobj);
1023 : : }
1024 : :
1025 : : #if defined(HAVE_LARGEFILE_SUPPORT)
1026 : : pos = PyLong_AsLongLong(posobj);
1027 : : #else
1028 : 0 : pos = PyLong_AsLong(posobj);
1029 : : #endif
1030 [ # # ]: 0 : if (PyErr_Occurred()){
1031 : 0 : Py_DECREF(posobj);
1032 : 0 : return NULL;
1033 : : }
1034 : :
1035 : 0 : Py_BEGIN_ALLOW_THREADS
1036 : : _Py_BEGIN_SUPPRESS_IPH
1037 : 0 : errno = 0;
1038 : : #ifdef MS_WINDOWS
1039 : : ret = _chsize_s(fd, pos);
1040 : : #else
1041 : 0 : ret = ftruncate(fd, pos);
1042 : : #endif
1043 : : _Py_END_SUPPRESS_IPH
1044 : 0 : Py_END_ALLOW_THREADS
1045 : :
1046 [ # # ]: 0 : if (ret != 0) {
1047 : 0 : Py_DECREF(posobj);
1048 : 0 : PyErr_SetFromErrno(PyExc_OSError);
1049 : 0 : return NULL;
1050 : : }
1051 : :
1052 : 0 : return posobj;
1053 : : }
1054 : : #endif /* HAVE_FTRUNCATE */
1055 : :
1056 : : static const char *
1057 : 0 : mode_string(fileio *self)
1058 : : {
1059 [ # # ]: 0 : if (self->created) {
1060 [ # # ]: 0 : if (self->readable)
1061 : 0 : return "xb+";
1062 : : else
1063 : 0 : return "xb";
1064 : : }
1065 [ # # ]: 0 : if (self->appending) {
1066 [ # # ]: 0 : if (self->readable)
1067 : 0 : return "ab+";
1068 : : else
1069 : 0 : return "ab";
1070 : : }
1071 [ # # ]: 0 : else if (self->readable) {
1072 [ # # ]: 0 : if (self->writable)
1073 : 0 : return "rb+";
1074 : : else
1075 : 0 : return "rb";
1076 : : }
1077 : : else
1078 : 0 : return "wb";
1079 : : }
1080 : :
1081 : : static PyObject *
1082 : 0 : fileio_repr(fileio *self)
1083 : : {
1084 : : PyObject *nameobj, *res;
1085 : :
1086 [ # # ]: 0 : if (self->fd < 0)
1087 : 0 : return PyUnicode_FromFormat("<_io.FileIO [closed]>");
1088 : :
1089 [ # # ]: 0 : if (_PyObject_LookupAttr((PyObject *) self, &_Py_ID(name), &nameobj) < 0) {
1090 : 0 : return NULL;
1091 : : }
1092 [ # # ]: 0 : if (nameobj == NULL) {
1093 : 0 : res = PyUnicode_FromFormat(
1094 : : "<_io.FileIO fd=%d mode='%s' closefd=%s>",
1095 [ # # ]: 0 : self->fd, mode_string(self), self->closefd ? "True" : "False");
1096 : : }
1097 : : else {
1098 : 0 : int status = Py_ReprEnter((PyObject *)self);
1099 : 0 : res = NULL;
1100 [ # # ]: 0 : if (status == 0) {
1101 : 0 : res = PyUnicode_FromFormat(
1102 : : "<_io.FileIO name=%R mode='%s' closefd=%s>",
1103 [ # # ]: 0 : nameobj, mode_string(self), self->closefd ? "True" : "False");
1104 : 0 : Py_ReprLeave((PyObject *)self);
1105 : : }
1106 [ # # ]: 0 : else if (status > 0) {
1107 : 0 : PyErr_Format(PyExc_RuntimeError,
1108 : : "reentrant call inside %s.__repr__",
1109 : 0 : Py_TYPE(self)->tp_name);
1110 : : }
1111 : 0 : Py_DECREF(nameobj);
1112 : : }
1113 : 0 : return res;
1114 : : }
1115 : :
1116 : : /*[clinic input]
1117 : : _io.FileIO.isatty
1118 : :
1119 : : True if the file is connected to a TTY device.
1120 : : [clinic start generated code]*/
1121 : :
1122 : : static PyObject *
1123 : 1416 : _io_FileIO_isatty_impl(fileio *self)
1124 : : /*[clinic end generated code: output=932c39924e9a8070 input=cd94ca1f5e95e843]*/
1125 : : {
1126 : : long res;
1127 : :
1128 [ - + ]: 1416 : if (self->fd < 0)
1129 : 0 : return err_closed();
1130 : 1416 : Py_BEGIN_ALLOW_THREADS
1131 : : _Py_BEGIN_SUPPRESS_IPH
1132 : 1416 : res = isatty(self->fd);
1133 : : _Py_END_SUPPRESS_IPH
1134 : 1416 : Py_END_ALLOW_THREADS
1135 : 1416 : return PyBool_FromLong(res);
1136 : : }
1137 : :
1138 : : #include "clinic/fileio.c.h"
1139 : :
1140 : : static PyMethodDef fileio_methods[] = {
1141 : : _IO_FILEIO_READ_METHODDEF
1142 : : _IO_FILEIO_READALL_METHODDEF
1143 : : _IO_FILEIO_READINTO_METHODDEF
1144 : : _IO_FILEIO_WRITE_METHODDEF
1145 : : _IO_FILEIO_SEEK_METHODDEF
1146 : : _IO_FILEIO_TELL_METHODDEF
1147 : : _IO_FILEIO_TRUNCATE_METHODDEF
1148 : : _IO_FILEIO_CLOSE_METHODDEF
1149 : : _IO_FILEIO_SEEKABLE_METHODDEF
1150 : : _IO_FILEIO_READABLE_METHODDEF
1151 : : _IO_FILEIO_WRITABLE_METHODDEF
1152 : : _IO_FILEIO_FILENO_METHODDEF
1153 : : _IO_FILEIO_ISATTY_METHODDEF
1154 : : {"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL},
1155 : : {NULL, NULL} /* sentinel */
1156 : : };
1157 : :
1158 : : /* 'closed' and 'mode' are attributes for backwards compatibility reasons. */
1159 : :
1160 : : static PyObject *
1161 : 154443 : get_closed(fileio *self, void *closure)
1162 : : {
1163 : 154443 : return PyBool_FromLong((long)(self->fd < 0));
1164 : : }
1165 : :
1166 : : static PyObject *
1167 : 0 : get_closefd(fileio *self, void *closure)
1168 : : {
1169 : 0 : return PyBool_FromLong((long)(self->closefd));
1170 : : }
1171 : :
1172 : : static PyObject *
1173 : 0 : get_mode(fileio *self, void *closure)
1174 : : {
1175 : 0 : return PyUnicode_FromString(mode_string(self));
1176 : : }
1177 : :
1178 : : static PyGetSetDef fileio_getsetlist[] = {
1179 : : {"closed", (getter)get_closed, NULL, "True if the file is closed"},
1180 : : {"closefd", (getter)get_closefd, NULL,
1181 : : "True if the file descriptor will be closed by close()."},
1182 : : {"mode", (getter)get_mode, NULL, "String giving the file mode"},
1183 : : {NULL},
1184 : : };
1185 : :
1186 : : static PyMemberDef fileio_members[] = {
1187 : : {"_blksize", T_UINT, offsetof(fileio, blksize), 0},
1188 : : {"_finalizing", T_BOOL, offsetof(fileio, finalizing), 0},
1189 : : {"__weaklistoffset__", T_PYSSIZET, offsetof(fileio, weakreflist), READONLY},
1190 : : {"__dictoffset__", T_PYSSIZET, offsetof(fileio, dict), READONLY},
1191 : : {NULL}
1192 : : };
1193 : :
1194 : : static PyType_Slot fileio_slots[] = {
1195 : : {Py_tp_dealloc, fileio_dealloc},
1196 : : {Py_tp_repr, fileio_repr},
1197 : : {Py_tp_doc, (void *)_io_FileIO___init____doc__},
1198 : : {Py_tp_traverse, fileio_traverse},
1199 : : {Py_tp_clear, fileio_clear},
1200 : : {Py_tp_methods, fileio_methods},
1201 : : {Py_tp_members, fileio_members},
1202 : : {Py_tp_getset, fileio_getsetlist},
1203 : : {Py_tp_init, _io_FileIO___init__},
1204 : : {Py_tp_new, fileio_new},
1205 : : {0, NULL},
1206 : : };
1207 : :
1208 : : PyType_Spec fileio_spec = {
1209 : : .name = "_io.FileIO",
1210 : : .basicsize = sizeof(fileio),
1211 : : .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
1212 : : Py_TPFLAGS_IMMUTABLETYPE),
1213 : : .slots = fileio_slots,
1214 : : };
|