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