Coverage Report

Created: 2025-08-26 06:57

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