1 /* Author: Daniel Stutzbach */
2 
3 #define PY_SSIZE_T_CLEAN
4 #include "Python.h"
5 #include "pycore_object.h"
6 #include "structmember.h"         // PyMemberDef
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 #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
_PyFileIO_closed(PyObject * self)82 _PyFileIO_closed(PyObject *self)
83 {
84     return ((fileio *)self)->fd < 0;
85 }
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 *
fileio_dealloc_warn(fileio * self,PyObject * source)91 fileio_dealloc_warn(fileio *self, PyObject *source)
92 {
93     if (self->fd >= 0 && self->closefd) {
94         PyObject *exc, *val, *tb;
95         PyErr_Fetch(&exc, &val, &tb);
96         if (PyErr_ResourceWarning(source, 1, "unclosed file %R", source)) {
97             /* Spurious errors can appear at shutdown */
98             if (PyErr_ExceptionMatches(PyExc_Warning))
99                 PyErr_WriteUnraisable((PyObject *) self);
100         }
101         PyErr_Restore(exc, val, tb);
102     }
103     Py_RETURN_NONE;
104 }
105 
106 /* Returns 0 on success, -1 with exception set on failure. */
107 static int
internal_close(fileio * self)108 internal_close(fileio *self)
109 {
110     int err = 0;
111     int save_errno = 0;
112     if (self->fd >= 0) {
113         int fd = self->fd;
114         self->fd = -1;
115         /* fd is accessible and someone else may have closed it */
116         Py_BEGIN_ALLOW_THREADS
117         _Py_BEGIN_SUPPRESS_IPH
118         err = close(fd);
119         if (err < 0)
120             save_errno = errno;
121         _Py_END_SUPPRESS_IPH
122         Py_END_ALLOW_THREADS
123     }
124     if (err < 0) {
125         errno = save_errno;
126         PyErr_SetFromErrno(PyExc_OSError);
127         return -1;
128     }
129     return 0;
130 }
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 *
_io_FileIO_close_impl(fileio * self)142 _io_FileIO_close_impl(fileio *self)
143 /*[clinic end generated code: output=7737a319ef3bad0b input=f35231760d54a522]*/
144 {
145     PyObject *res;
146     PyObject *exc, *val, *tb;
147     int rc;
148     _Py_IDENTIFIER(close);
149     res = _PyObject_CallMethodIdOneArg((PyObject*)&PyRawIOBase_Type,
150                                        &PyId_close, (PyObject *)self);
151     if (!self->closefd) {
152         self->fd = -1;
153         return res;
154     }
155     if (res == NULL)
156         PyErr_Fetch(&exc, &val, &tb);
157     if (self->finalizing) {
158         PyObject *r = fileio_dealloc_warn(self, (PyObject *) self);
159         if (r)
160             Py_DECREF(r);
161         else
162             PyErr_Clear();
163     }
164     rc = internal_close(self);
165     if (res == NULL)
166         _PyErr_ChainExceptions(exc, val, tb);
167     if (rc < 0)
168         Py_CLEAR(res);
169     return res;
170 }
171 
172 static PyObject *
fileio_new(PyTypeObject * type,PyObject * args,PyObject * kwds)173 fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
174 {
175     fileio *self;
176 
177     assert(type != NULL && type->tp_alloc != NULL);
178 
179     self = (fileio *) type->tp_alloc(type, 0);
180     if (self != NULL) {
181         self->fd = -1;
182         self->created = 0;
183         self->readable = 0;
184         self->writable = 0;
185         self->appending = 0;
186         self->seekable = -1;
187         self->blksize = 0;
188         self->closefd = 1;
189         self->weakreflist = NULL;
190     }
191 
192     return (PyObject *) self;
193 }
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
_io_FileIO___init___impl(fileio * self,PyObject * nameobj,const char * mode,int closefd,PyObject * opener)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 {
226 #ifdef MS_WINDOWS
227     Py_UNICODE *widename = NULL;
228 #else
229     const char *name = NULL;
230 #endif
231     PyObject *stringobj = NULL;
232     const char *s;
233     int ret = 0;
234     int rwa = 0, plus = 0;
235     int flags = 0;
236     int fd = -1;
237     int fd_is_own = 0;
238 #ifdef O_CLOEXEC
239     int *atomic_flag_works = &_Py_open_cloexec_works;
240 #elif !defined(MS_WINDOWS)
241     int *atomic_flag_works = NULL;
242 #endif
243     struct _Py_stat_struct fdfstat;
244     int fstat_result;
245     int async_err = 0;
246 
247     assert(PyFileIO_Check(self));
248     if (self->fd >= 0) {
249         if (self->closefd) {
250             /* Have to close the existing file first. */
251             if (internal_close(self) < 0)
252                 return -1;
253         }
254         else
255             self->fd = -1;
256     }
257 
258     if (PyFloat_Check(nameobj)) {
259         PyErr_SetString(PyExc_TypeError,
260                         "integer argument expected, got float");
261         return -1;
262     }
263 
264     fd = _PyLong_AsInt(nameobj);
265     if (fd < 0) {
266         if (!PyErr_Occurred()) {
267             PyErr_SetString(PyExc_ValueError,
268                             "negative file descriptor");
269             return -1;
270         }
271         PyErr_Clear();
272     }
273 
274     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         if (!PyUnicode_FSConverter(nameobj, &stringobj)) {
284             return -1;
285         }
286         name = PyBytes_AS_STRING(stringobj);
287 #endif
288     }
289 
290     s = mode;
291     while (*s) {
292         switch (*s++) {
293         case 'x':
294             if (rwa) {
295             bad_mode:
296                 PyErr_SetString(PyExc_ValueError,
297                                 "Must have exactly one of create/read/write/append "
298                                 "mode and at most one plus");
299                 goto error;
300             }
301             rwa = 1;
302             self->created = 1;
303             self->writable = 1;
304             flags |= O_EXCL | O_CREAT;
305             break;
306         case 'r':
307             if (rwa)
308                 goto bad_mode;
309             rwa = 1;
310             self->readable = 1;
311             break;
312         case 'w':
313             if (rwa)
314                 goto bad_mode;
315             rwa = 1;
316             self->writable = 1;
317             flags |= O_CREAT | O_TRUNC;
318             break;
319         case 'a':
320             if (rwa)
321                 goto bad_mode;
322             rwa = 1;
323             self->writable = 1;
324             self->appending = 1;
325             flags |= O_APPEND | O_CREAT;
326             break;
327         case 'b':
328             break;
329         case '+':
330             if (plus)
331                 goto bad_mode;
332             self->readable = self->writable = 1;
333             plus = 1;
334             break;
335         default:
336             PyErr_Format(PyExc_ValueError,
337                          "invalid mode: %.200s", mode);
338             goto error;
339         }
340     }
341 
342     if (!rwa)
343         goto bad_mode;
344 
345     if (self->readable && self->writable)
346         flags |= O_RDWR;
347     else if (self->readable)
348         flags |= O_RDONLY;
349     else
350         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 #endif
361 
362     if (PySys_Audit("open", "Osi", nameobj, mode, flags) < 0) {
363         goto error;
364     }
365 
366     if (fd >= 0) {
367         self->fd = fd;
368         self->closefd = closefd;
369     }
370     else {
371         self->closefd = 1;
372         if (!closefd) {
373             PyErr_SetString(PyExc_ValueError,
374                 "Cannot use closefd=False with file name");
375             goto error;
376         }
377 
378         errno = 0;
379         if (opener == Py_None) {
380             do {
381                 Py_BEGIN_ALLOW_THREADS
382 #ifdef MS_WINDOWS
383                 self->fd = _wopen(widename, flags, 0666);
384 #else
385                 self->fd = open(name, flags, 0666);
386 #endif
387                 Py_END_ALLOW_THREADS
388             } while (self->fd < 0 && errno == EINTR &&
389                      !(async_err = PyErr_CheckSignals()));
390 
391             if (async_err)
392                 goto error;
393         }
394         else {
395             PyObject *fdobj;
396 
397 #ifndef MS_WINDOWS
398             /* the opener may clear the atomic flag */
399             atomic_flag_works = NULL;
400 #endif
401 
402             fdobj = PyObject_CallFunction(opener, "Oi", nameobj, flags);
403             if (fdobj == NULL)
404                 goto error;
405             if (!PyLong_Check(fdobj)) {
406                 Py_DECREF(fdobj);
407                 PyErr_SetString(PyExc_TypeError,
408                         "expected integer from opener");
409                 goto error;
410             }
411 
412             self->fd = _PyLong_AsInt(fdobj);
413             Py_DECREF(fdobj);
414             if (self->fd < 0) {
415                 if (!PyErr_Occurred()) {
416                     /* The opener returned a negative but didn't set an
417                        exception.  See issue #27066 */
418                     PyErr_Format(PyExc_ValueError,
419                                  "opener returned %d", self->fd);
420                 }
421                 goto error;
422             }
423         }
424 
425         fd_is_own = 1;
426         if (self->fd < 0) {
427             PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
428             goto error;
429         }
430 
431 #ifndef MS_WINDOWS
432         if (_Py_set_inheritable(self->fd, 0, atomic_flag_works) < 0)
433             goto error;
434 #endif
435     }
436 
437     self->blksize = DEFAULT_BUFFER_SIZE;
438     Py_BEGIN_ALLOW_THREADS
439     fstat_result = _Py_fstat_noraise(self->fd, &fdfstat);
440     Py_END_ALLOW_THREADS
441     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         if (errno == EBADF) {
450             PyErr_SetFromErrno(PyExc_OSError);
451 #endif
452             goto error;
453         }
454     }
455     else {
456 #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         if (S_ISDIR(fdfstat.st_mode)) {
461             errno = EISDIR;
462             PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
463             goto error;
464         }
465 #endif /* defined(S_ISDIR) */
466 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
467         if (fdfstat.st_blksize > 1)
468             self->blksize = fdfstat.st_blksize;
469 #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
470     }
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     if (_PyObject_SetAttrId((PyObject *)self, &PyId_name, nameobj) < 0)
478         goto error;
479 
480     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         PyObject *pos = portable_lseek(self, NULL, 2, true);
485         if (pos == NULL)
486             goto error;
487         Py_DECREF(pos);
488     }
489 
490     goto done;
491 
492  error:
493     ret = -1;
494     if (!fd_is_own)
495         self->fd = -1;
496     if (self->fd >= 0)
497         internal_close(self);
498 
499  done:
500     Py_CLEAR(stringobj);
501     return ret;
502 }
503 
504 static int
505 fileio_traverse(fileio *self, visitproc visit, void *arg)
506 {
507     Py_VISIT(self->dict);
508     return 0;
509 }
510 
511 static int
512 fileio_clear(fileio *self)
513 {
514     Py_CLEAR(self->dict);
515     return 0;
516 }
517 
518 static void
519 fileio_dealloc(fileio *self)
520 {
521     self->finalizing = 1;
522     if (_PyIOBase_finalize((PyObject *) self) < 0)
523         return;
524     _PyObject_GC_UNTRACK(self);
525     if (self->weakreflist != NULL)
526         PyObject_ClearWeakRefs((PyObject *) self);
527     Py_CLEAR(self->dict);
528     Py_TYPE(self)->tp_free((PyObject *)self);
529 }
530 
531 static PyObject *
532 err_closed(void)
533 {
534     PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
535     return NULL;
536 }
537 
538 static PyObject *
539 err_mode(const char *action)
540 {
541     _PyIO_State *state = IO_STATE();
542     if (state != NULL)
543         PyErr_Format(state->unsupported_operation,
544                      "File not open for %s", action);
545     return NULL;
546 }
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 {
558     if (self->fd < 0)
559         return err_closed();
560     return PyLong_FromLong((long) self->fd);
561 }
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 {
573     if (self->fd < 0)
574         return err_closed();
575     return PyBool_FromLong((long) self->readable);
576 }
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 {
588     if (self->fd < 0)
589         return err_closed();
590     return PyBool_FromLong((long) self->writable);
591 }
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 {
603     if (self->fd < 0)
604         return err_closed();
605     if (self->seekable < 0) {
606         /* portable_lseek() sets the seekable attribute */
607         PyObject *pos = portable_lseek(self, NULL, SEEK_CUR, false);
608         assert(self->seekable >= 0);
609         if (pos == NULL) {
610             PyErr_Clear();
611         }
612         else {
613             Py_DECREF(pos);
614         }
615     }
616     return PyBool_FromLong((long) self->seekable);
617 }
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 {
631     Py_ssize_t n;
632     int err;
633 
634     if (self->fd < 0)
635         return err_closed();
636     if (!self->readable)
637         return err_mode("reading");
638 
639     n = _Py_read(self->fd, buffer->buf, buffer->len);
640     /* copy errno because PyBuffer_Release() can indirectly modify it */
641     err = errno;
642 
643     if (n == -1) {
644         if (err == EAGAIN) {
645             PyErr_Clear();
646             Py_RETURN_NONE;
647         }
648         return NULL;
649     }
650 
651     return PyLong_FromSsize_t(n);
652 }
653 
654 static size_t
655 new_buffersize(fileio *self, size_t currentsize)
656 {
657     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     assert(currentsize <= PY_SSIZE_T_MAX);
663     if (currentsize > 65536)
664         addend = currentsize >> 3;
665     else
666         addend = 256 + currentsize;
667     if (addend < SMALLCHUNK)
668         /* Avoid tiny read() calls. */
669         addend = SMALLCHUNK;
670     return addend + currentsize;
671 }
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 {
686     struct _Py_stat_struct status;
687     Py_off_t pos, end;
688     PyObject *result;
689     Py_ssize_t bytes_read = 0;
690     Py_ssize_t n;
691     size_t bufsize;
692     int fstat_result;
693 
694     if (self->fd < 0)
695         return err_closed();
696 
697     Py_BEGIN_ALLOW_THREADS
698     _Py_BEGIN_SUPPRESS_IPH
699 #ifdef MS_WINDOWS
700     pos = _lseeki64(self->fd, 0L, SEEK_CUR);
701 #else
702     pos = lseek(self->fd, 0L, SEEK_CUR);
703 #endif
704     _Py_END_SUPPRESS_IPH
705     fstat_result = _Py_fstat_noraise(self->fd, &status);
706     Py_END_ALLOW_THREADS
707 
708     if (fstat_result == 0)
709         end = status.st_size;
710     else
711         end = (Py_off_t)-1;
712 
713     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         bufsize = (size_t)(end - pos + 1);
719     } else {
720         bufsize = SMALLCHUNK;
721     }
722 
723     result = PyBytes_FromStringAndSize(NULL, bufsize);
724     if (result == NULL)
725         return NULL;
726 
727     while (1) {
728         if (bytes_read >= (Py_ssize_t)bufsize) {
729             bufsize = new_buffersize(self, bytes_read);
730             if (bufsize > PY_SSIZE_T_MAX || bufsize <= 0) {
731                 PyErr_SetString(PyExc_OverflowError,
732                                 "unbounded read returned more bytes "
733                                 "than a Python bytes object can hold");
734                 Py_DECREF(result);
735                 return NULL;
736             }
737 
738             if (PyBytes_GET_SIZE(result) < (Py_ssize_t)bufsize) {
739                 if (_PyBytes_Resize(&result, bufsize) < 0)
740                     return NULL;
741             }
742         }
743 
744         n = _Py_read(self->fd,
745                      PyBytes_AS_STRING(result) + bytes_read,
746                      bufsize - bytes_read);
747 
748         if (n == 0)
749             break;
750         if (n == -1) {
751             if (errno == EAGAIN) {
752                 PyErr_Clear();
753                 if (bytes_read > 0)
754                     break;
755                 Py_DECREF(result);
756                 Py_RETURN_NONE;
757             }
758             Py_DECREF(result);
759             return NULL;
760         }
761         bytes_read += n;
762         pos += n;
763     }
764 
765     if (PyBytes_GET_SIZE(result) > bytes_read) {
766         if (_PyBytes_Resize(&result, bytes_read) < 0)
767             return NULL;
768     }
769     return result;
770 }
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 {
788     char *ptr;
789     Py_ssize_t n;
790     PyObject *bytes;
791 
792     if (self->fd < 0)
793         return err_closed();
794     if (!self->readable)
795         return err_mode("reading");
796 
797     if (size < 0)
798         return _io_FileIO_readall_impl(self);
799 
800     if (size > _PY_READ_MAX) {
801         size = _PY_READ_MAX;
802     }
803 
804     bytes = PyBytes_FromStringAndSize(NULL, size);
805     if (bytes == NULL)
806         return NULL;
807     ptr = PyBytes_AS_STRING(bytes);
808 
809     n = _Py_read(self->fd, ptr, size);
810     if (n == -1) {
811         /* copy errno because Py_DECREF() can indirectly modify it */
812         int err = errno;
813         Py_DECREF(bytes);
814         if (err == EAGAIN) {
815             PyErr_Clear();
816             Py_RETURN_NONE;
817         }
818         return NULL;
819     }
820 
821     if (n != size) {
822         if (_PyBytes_Resize(&bytes, n) < 0) {
823             Py_CLEAR(bytes);
824             return NULL;
825         }
826     }
827 
828     return (PyObject *) bytes;
829 }
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 {
847     Py_ssize_t n;
848     int err;
849 
850     if (self->fd < 0)
851         return err_closed();
852     if (!self->writable)
853         return err_mode("writing");
854 
855     n = _Py_write(self->fd, b->buf, b->len);
856     /* copy errno because PyBuffer_Release() can indirectly modify it */
857     err = errno;
858 
859     if (n < 0) {
860         if (err == EAGAIN) {
861             PyErr_Clear();
862             Py_RETURN_NONE;
863         }
864         return NULL;
865     }
866 
867     return PyLong_FromSsize_t(n);
868 }
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 {
876     Py_off_t pos, res;
877     int fd = self->fd;
878 
879 #ifdef SEEK_SET
880     /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
881     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     }
892 #endif /* SEEK_SET */
893 
894     if (posobj == NULL) {
895         pos = 0;
896     }
897     else {
898         if(PyFloat_Check(posobj)) {
899             PyErr_SetString(PyExc_TypeError, "an integer is required");
900             return NULL;
901         }
902 #if defined(HAVE_LARGEFILE_SUPPORT)
903         pos = PyLong_AsLongLong(posobj);
904 #else
905         pos = PyLong_AsLong(posobj);
906 #endif
907         if (PyErr_Occurred())
908             return NULL;
909     }
910 
911     Py_BEGIN_ALLOW_THREADS
912     _Py_BEGIN_SUPPRESS_IPH
913 #ifdef MS_WINDOWS
914     res = _lseeki64(fd, pos, whence);
915 #else
916     res = lseek(fd, pos, whence);
917 #endif
918     _Py_END_SUPPRESS_IPH
919     Py_END_ALLOW_THREADS
920 
921     if (self->seekable < 0) {
922         self->seekable = (res >= 0);
923     }
924 
925     if (res < 0) {
926         if (suppress_pipe_error && errno == ESPIPE) {
927             res = 0;
928         } else {
929             return PyErr_SetFromErrno(PyExc_OSError);
930         }
931     }
932 
933 #if defined(HAVE_LARGEFILE_SUPPORT)
934     return PyLong_FromLongLong(res);
935 #else
936     return PyLong_FromLong(res);
937 #endif
938 }
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 {
961     if (self->fd < 0)
962         return err_closed();
963 
964     return portable_lseek(self, pos, whence, false);
965 }
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 {
979     if (self->fd < 0)
980         return err_closed();
981 
982     return portable_lseek(self, NULL, 1, false);
983 }
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 {
1001     Py_off_t pos;
1002     int ret;
1003     int fd;
1004 
1005     fd = self->fd;
1006     if (fd < 0)
1007         return err_closed();
1008     if (!self->writable)
1009         return err_mode("writing");
1010 
1011     if (posobj == Py_None) {
1012         /* Get the current position. */
1013         posobj = portable_lseek(self, NULL, 1, false);
1014         if (posobj == NULL)
1015             return NULL;
1016     }
1017     else {
1018         Py_INCREF(posobj);
1019     }
1020 
1021 #if defined(HAVE_LARGEFILE_SUPPORT)
1022     pos = PyLong_AsLongLong(posobj);
1023 #else
1024     pos = PyLong_AsLong(posobj);
1025 #endif
1026     if (PyErr_Occurred()){
1027         Py_DECREF(posobj);
1028         return NULL;
1029     }
1030 
1031     Py_BEGIN_ALLOW_THREADS
1032     _Py_BEGIN_SUPPRESS_IPH
1033     errno = 0;
1034 #ifdef MS_WINDOWS
1035     ret = _chsize_s(fd, pos);
1036 #else
1037     ret = ftruncate(fd, pos);
1038 #endif
1039     _Py_END_SUPPRESS_IPH
1040     Py_END_ALLOW_THREADS
1041 
1042     if (ret != 0) {
1043         Py_DECREF(posobj);
1044         PyErr_SetFromErrno(PyExc_OSError);
1045         return NULL;
1046     }
1047 
1048     return posobj;
1049 }
1050 #endif /* HAVE_FTRUNCATE */
1051 
1052 static const char *
1053 mode_string(fileio *self)
1054 {
1055     if (self->created) {
1056         if (self->readable)
1057             return "xb+";
1058         else
1059             return "xb";
1060     }
1061     if (self->appending) {
1062         if (self->readable)
1063             return "ab+";
1064         else
1065             return "ab";
1066     }
1067     else if (self->readable) {
1068         if (self->writable)
1069             return "rb+";
1070         else
1071             return "rb";
1072     }
1073     else
1074         return "wb";
1075 }
1076 
1077 static PyObject *
1078 fileio_repr(fileio *self)
1079 {
1080     PyObject *nameobj, *res;
1081 
1082     if (self->fd < 0)
1083         return PyUnicode_FromFormat("<_io.FileIO [closed]>");
1084 
1085     if (_PyObject_LookupAttrId((PyObject *) self, &PyId_name, &nameobj) < 0) {
1086         return NULL;
1087     }
1088     if (nameobj == NULL) {
1089         res = PyUnicode_FromFormat(
1090             "<_io.FileIO fd=%d mode='%s' closefd=%s>",
1091             self->fd, mode_string(self), self->closefd ? "True" : "False");
1092     }
1093     else {
1094         int status = Py_ReprEnter((PyObject *)self);
1095         res = NULL;
1096         if (status == 0) {
1097             res = PyUnicode_FromFormat(
1098                 "<_io.FileIO name=%R mode='%s' closefd=%s>",
1099                 nameobj, mode_string(self), self->closefd ? "True" : "False");
1100             Py_ReprLeave((PyObject *)self);
1101         }
1102         else if (status > 0) {
1103             PyErr_Format(PyExc_RuntimeError,
1104                          "reentrant call inside %s.__repr__",
1105                          Py_TYPE(self)->tp_name);
1106         }
1107         Py_DECREF(nameobj);
1108     }
1109     return res;
1110 }
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 {
1122     long res;
1123 
1124     if (self->fd < 0)
1125         return err_closed();
1126     Py_BEGIN_ALLOW_THREADS
1127     _Py_BEGIN_SUPPRESS_IPH
1128     res = isatty(self->fd);
1129     _Py_END_SUPPRESS_IPH
1130     Py_END_ALLOW_THREADS
1131     return PyBool_FromLong(res);
1132 }
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 {
1159     return PyBool_FromLong((long)(self->fd < 0));
1160 }
1161 
1162 static PyObject *
1163 get_closefd(fileio *self, void *closure)
1164 {
1165     return PyBool_FromLong((long)(self->closefd));
1166 }
1167 
1168 static PyObject *
1169 get_mode(fileio *self, void *closure)
1170 {
1171     return PyUnicode_FromString(mode_string(self));
1172 }
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 };
1239