Coverage Report

Created: 2025-07-11 06:59

/src/Python-3.8.3/Modules/_io/fileio.c
Line
Count
Source (jump to first uncovered line)
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
558
{
84
558
    return ((fileio *)self)->fd < 0;
85
558
}
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
236
{
110
236
    int err = 0;
111
236
    int save_errno = 0;
112
236
    if (self->fd >= 0) {
113
236
        int fd = self->fd;
114
236
        self->fd = -1;
115
        /* fd is accessible and someone else may have closed it */
116
236
        Py_BEGIN_ALLOW_THREADS
117
236
        _Py_BEGIN_SUPPRESS_IPH
118
236
        err = close(fd);
119
236
        if (err < 0)
120
0
            save_errno = errno;
121
236
        _Py_END_SUPPRESS_IPH
122
236
        Py_END_ALLOW_THREADS
123
236
    }
124
236
    if (err < 0) {
125
0
        errno = save_errno;
126
0
        PyErr_SetFromErrno(PyExc_OSError);
127
0
        return -1;
128
0
    }
129
236
    return 0;
130
236
}
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
236
{
145
236
    PyObject *res;
146
236
    PyObject *exc, *val, *tb;
147
236
    int rc;
148
236
    _Py_IDENTIFIER(close);
149
236
    res = _PyObject_CallMethodIdObjArgs((PyObject*)&PyRawIOBase_Type,
150
236
                                        &PyId_close, self, NULL);
151
236
    if (!self->closefd) {
152
0
        self->fd = -1;
153
0
        return res;
154
0
    }
155
236
    if (res == NULL)
156
0
        PyErr_Fetch(&exc, &val, &tb);
157
236
    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
236
    rc = internal_close(self);
165
236
    if (res == NULL)
166
0
        _PyErr_ChainExceptions(exc, val, tb);
167
236
    if (rc < 0)
168
0
        Py_CLEAR(res);
169
236
    return res;
170
236
}
171
172
static PyObject *
173
fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
174
278
{
175
278
    fileio *self;
176
177
278
    assert(type != NULL && type->tp_alloc != NULL);
178
179
278
    self = (fileio *) type->tp_alloc(type, 0);
180
278
    if (self != NULL) {
181
278
        self->fd = -1;
182
278
        self->created = 0;
183
278
        self->readable = 0;
184
278
        self->writable = 0;
185
278
        self->appending = 0;
186
278
        self->seekable = -1;
187
278
        self->blksize = 0;
188
278
        self->closefd = 1;
189
278
        self->weakreflist = NULL;
190
278
    }
191
192
278
    return (PyObject *) self;
193
278
}
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
278
{
226
#ifdef MS_WINDOWS
227
    Py_UNICODE *widename = NULL;
228
#else
229
278
    const char *name = NULL;
230
278
#endif
231
278
    PyObject *stringobj = NULL;
232
278
    const char *s;
233
278
    int ret = 0;
234
278
    int rwa = 0, plus = 0;
235
278
    int flags = 0;
236
278
    int fd = -1;
237
278
    int fd_is_own = 0;
238
278
#ifdef O_CLOEXEC
239
278
    int *atomic_flag_works = &_Py_open_cloexec_works;
240
#elif !defined(MS_WINDOWS)
241
    int *atomic_flag_works = NULL;
242
#endif
243
278
    struct _Py_stat_struct fdfstat;
244
278
    int fstat_result;
245
278
    int async_err = 0;
246
247
278
    assert(PyFileIO_Check(self));
248
278
    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
278
    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
278
    fd = _PyLong_AsInt(nameobj);
265
278
    if (fd < 0) {
266
236
        if (!PyErr_Occurred()) {
267
0
            PyErr_SetString(PyExc_ValueError,
268
0
                            "negative file descriptor");
269
0
            return -1;
270
0
        }
271
236
        PyErr_Clear();
272
236
    }
273
274
278
    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
236
        if (!PyUnicode_FSConverter(nameobj, &stringobj)) {
284
0
            return -1;
285
0
        }
286
236
        name = PyBytes_AS_STRING(stringobj);
287
236
#endif
288
236
    }
289
290
278
    s = mode;
291
556
    while (*s) {
292
278
        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
250
        case 'r':
307
250
            if (rwa)
308
0
                goto bad_mode;
309
250
            rwa = 1;
310
250
            self->readable = 1;
311
250
            break;
312
28
        case 'w':
313
28
            if (rwa)
314
0
                goto bad_mode;
315
28
            rwa = 1;
316
28
            self->writable = 1;
317
28
            flags |= O_CREAT | O_TRUNC;
318
28
            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
278
        }
340
278
    }
341
342
278
    if (!rwa)
343
0
        goto bad_mode;
344
345
278
    if (self->readable && self->writable)
346
0
        flags |= O_RDWR;
347
278
    else if (self->readable)
348
250
        flags |= O_RDONLY;
349
28
    else
350
28
        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
    flags |= O_CLOEXEC;
360
278
#endif
361
362
278
    if (PySys_Audit("open", "Osi", nameobj, mode, flags) < 0) {
363
0
        goto error;
364
0
    }
365
366
278
    if (fd >= 0) {
367
42
        self->fd = fd;
368
42
        self->closefd = closefd;
369
42
    }
370
236
    else {
371
236
        self->closefd = 1;
372
236
        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
236
        errno = 0;
379
236
        if (opener == Py_None) {
380
236
            do {
381
236
                Py_BEGIN_ALLOW_THREADS
382
#ifdef MS_WINDOWS
383
                self->fd = _wopen(widename, flags, 0666);
384
#else
385
236
                self->fd = open(name, flags, 0666);
386
236
#endif
387
236
                Py_END_ALLOW_THREADS
388
236
            } while (self->fd < 0 && errno == EINTR &&
389
236
                     !(async_err = PyErr_CheckSignals()));
390
391
236
            if (async_err)
392
0
                goto error;
393
236
        }
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
236
        fd_is_own = 1;
426
236
        if (self->fd < 0) {
427
0
            PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
428
0
            goto error;
429
0
        }
430
431
236
#ifndef MS_WINDOWS
432
236
        if (_Py_set_inheritable(self->fd, 0, atomic_flag_works) < 0)
433
0
            goto error;
434
236
#endif
435
236
    }
436
437
278
    self->blksize = DEFAULT_BUFFER_SIZE;
438
278
    Py_BEGIN_ALLOW_THREADS
439
278
    fstat_result = _Py_fstat_noraise(self->fd, &fdfstat);
440
278
    Py_END_ALLOW_THREADS
441
278
    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
278
    else {
456
278
#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
278
        if (S_ISDIR(fdfstat.st_mode)) {
461
0
            errno = EISDIR;
462
0
            PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
463
0
            goto error;
464
0
        }
465
278
#endif /* defined(S_ISDIR) */
466
278
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
467
278
        if (fdfstat.st_blksize > 1)
468
278
            self->blksize = fdfstat.st_blksize;
469
278
#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
470
278
    }
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
278
    if (_PyObject_SetAttrId((PyObject *)self, &PyId_name, nameobj) < 0)
478
0
        goto error;
479
480
278
    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
278
    goto done;
491
492
278
 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
278
 done:
500
278
    Py_CLEAR(stringobj);
501
278
    return ret;
502
0
}
503
504
static int
505
fileio_traverse(fileio *self, visitproc visit, void *arg)
506
90
{
507
90
    Py_VISIT(self->dict);
508
90
    return 0;
509
90
}
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
236
{
521
236
    self->finalizing = 1;
522
236
    if (_PyIOBase_finalize((PyObject *) self) < 0)
523
0
        return;
524
236
    _PyObject_GC_UNTRACK(self);
525
236
    if (self->weakreflist != NULL)
526
0
        PyObject_ClearWeakRefs((PyObject *) self);
527
236
    Py_CLEAR(self->dict);
528
236
    Py_TYPE(self)->tp_free((PyObject *)self);
529
236
}
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
265
{
573
265
    if (self->fd < 0)
574
0
        return err_closed();
575
265
    return PyBool_FromLong((long) self->readable);
576
265
}
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
56
{
588
56
    if (self->fd < 0)
589
0
        return err_closed();
590
56
    return PyBool_FromLong((long) self->writable);
591
56
}
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
44
{
603
44
    if (self->fd < 0)
604
0
        return err_closed();
605
44
    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
44
    return PyBool_FromLong((long) self->seekable);
617
44
}
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
235
{
686
235
    struct _Py_stat_struct status;
687
235
    Py_off_t pos, end;
688
235
    PyObject *result;
689
235
    Py_ssize_t bytes_read = 0;
690
235
    Py_ssize_t n;
691
235
    size_t bufsize;
692
235
    int fstat_result;
693
694
235
    if (self->fd < 0)
695
0
        return err_closed();
696
697
235
    Py_BEGIN_ALLOW_THREADS
698
235
    _Py_BEGIN_SUPPRESS_IPH
699
#ifdef MS_WINDOWS
700
    pos = _lseeki64(self->fd, 0L, SEEK_CUR);
701
#else
702
235
    pos = lseek(self->fd, 0L, SEEK_CUR);
703
235
#endif
704
235
    _Py_END_SUPPRESS_IPH
705
235
    fstat_result = _Py_fstat_noraise(self->fd, &status);
706
235
    Py_END_ALLOW_THREADS
707
708
235
    if (fstat_result == 0)
709
235
        end = status.st_size;
710
0
    else
711
0
        end = (Py_off_t)-1;
712
713
235
    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
235
        bufsize = (size_t)(end - pos + 1);
719
235
    } else {
720
0
        bufsize = SMALLCHUNK;
721
0
    }
722
723
235
    result = PyBytes_FromStringAndSize(NULL, bufsize);
724
235
    if (result == NULL)
725
0
        return NULL;
726
727
470
    while (1) {
728
470
        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
470
        n = _Py_read(self->fd,
745
470
                     PyBytes_AS_STRING(result) + bytes_read,
746
470
                     bufsize - bytes_read);
747
748
470
        if (n == 0)
749
235
            break;
750
235
        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
235
        bytes_read += n;
762
235
        pos += n;
763
235
    }
764
765
235
    if (PyBytes_GET_SIZE(result) > bytes_read) {
766
235
        if (_PyBytes_Resize(&result, bytes_read) < 0)
767
0
            return NULL;
768
235
    }
769
235
    return result;
770
235
}
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
306
{
876
306
    Py_off_t pos, res;
877
306
    int fd = self->fd;
878
879
306
#ifdef SEEK_SET
880
    /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
881
306
    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
306
    }
892
306
#endif /* SEEK_SET */
893
894
306
    if (posobj == NULL) {
895
306
        pos = 0;
896
306
    }
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
306
    Py_BEGIN_ALLOW_THREADS
912
306
    _Py_BEGIN_SUPPRESS_IPH
913
#ifdef MS_WINDOWS
914
    res = _lseeki64(fd, pos, whence);
915
#else
916
306
    res = lseek(fd, pos, whence);
917
306
#endif
918
306
    _Py_END_SUPPRESS_IPH
919
306
    Py_END_ALLOW_THREADS
920
921
306
    if (self->seekable < 0) {
922
278
        self->seekable = (res >= 0);
923
278
    }
924
925
306
    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
306
    return PyLong_FromLong(res);
937
306
#endif
938
306
}
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
306
{
979
306
    if (self->fd < 0)
980
0
        return err_closed();
981
982
306
    return portable_lseek(self, NULL, 1, false);
983
306
}
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
320
{
1122
320
    long res;
1123
1124
320
    if (self->fd < 0)
1125
0
        return err_closed();
1126
320
    Py_BEGIN_ALLOW_THREADS
1127
320
    _Py_BEGIN_SUPPRESS_IPH
1128
320
    res = isatty(self->fd);
1129
320
    _Py_END_SUPPRESS_IPH
1130
320
    Py_END_ALLOW_THREADS
1131
320
    return PyBool_FromLong(res);
1132
320
}
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
947
{
1159
947
    return PyBool_FromLong((long)(self->fd < 0));
1160
947
}
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
};