Coverage Report

Created: 2026-06-14 06:25

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