Coverage Report

Created: 2026-06-07 06:26

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