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]
53 module _io
54 class _io.FileIO "fileio *" "&PyFileIO_Type"
55 [clinic start generated code]*/
56 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=1c77708b41fda70c]*/
57 
58 typedef 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 
73 PyTypeObject PyFileIO_Type;
74 
75 #define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type))
76 
77 /* Forward declarations */
78 static PyObject* portable_lseek(fileio *self, PyObject *posobj, int whence, bool suppress_pipe_error);
79 
80 int
_PyFileIO_closed(PyObject * self)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). */
89 static PyObject *
fileio_dealloc_warn(fileio * self,PyObject * source)90 fileio_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. */
106 static int
internal_close(fileio * self)107 internal_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 
134 Close the file.
135 
136 A closed file cannot be used for further I/O operations.  close() may be
137 called more than once without error.
138 [clinic start generated code]*/
139 
140 static PyObject *
_io_FileIO_close_impl(fileio * self)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 
170 static PyObject *
fileio_new(PyTypeObject * type,PyObject * args,PyObject * kwds)171 fileio_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
194 extern 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 
204 Open a file.
205 
206 The mode can be 'r' (default), 'w', 'x' or 'a' for reading,
207 writing, exclusive creation or appending.  The file will be created if it
208 doesn't exist when opened for writing or appending; it will be truncated
209 when opened for writing.  A FileExistsError will be raised if it already
210 exists when opened for creating. Opening a file for creating implies
211 writing so this mode behaves in a similar way to 'w'.Add a '+' to the mode
212 to allow simultaneous reading and writing. A custom opener can be used by
213 passing a callable as *opener*. The underlying file descriptor for the file
214 object is then obtained by calling opener with (*name*, *flags*).
215 *opener* must return an open file descriptor (passing os.open as *opener*
216 results in functionality similar to passing None).
217 [clinic start generated code]*/
218 
219 static int
_io_FileIO___init___impl(fileio * self,PyObject * nameobj,const char * mode,int closefd,PyObject * opener)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 
512 static int
513 fileio_traverse(fileio *self, visitproc visit, void *arg)
514 {
515     Py_VISIT(self->dict);
516     return 0;
517 }
518 
519 static int
520 fileio_clear(fileio *self)
521 {
522     Py_CLEAR(self->dict);
523     return 0;
524 }
525 
526 static void
527 fileio_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 
539 static PyObject *
540 err_closed(void)
541 {
542     PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
543     return NULL;
544 }
545 
546 static PyObject *
547 err_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 
559 Return the underlying file descriptor (an integer).
560 [clinic start generated code]*/
561 
562 static 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 
574 True if file was opened in a read mode.
575 [clinic start generated code]*/
576 
577 static 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 
589 True if file was opened in a write mode.
590 [clinic start generated code]*/
591 
592 static 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 
604 True if file supports random-access.
605 [clinic start generated code]*/
606 
607 static 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 
632 Same as RawIOBase.readinto().
633 [clinic start generated code]*/
634 
635 static 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 
662 static size_t
663 new_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 
684 Read all data from the file, returned as bytes.
685 
686 In non-blocking mode, returns as much as is immediately available,
687 or None if no data is available.  Return an empty bytes object at EOF.
688 [clinic start generated code]*/
689 
690 static 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 
785 Read at most size bytes, returned as bytes.
786 
787 Only makes one system call, so less data may be returned than requested.
788 In non-blocking mode, returns None if no data is available.
789 Return an empty bytes object at EOF.
790 [clinic start generated code]*/
791 
792 static 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 
844 Write buffer b to file, return number of bytes written.
845 
846 Only makes one system call, so not all of the data may be written.
847 The number of bytes actually written is returned.  In non-blocking mode,
848 returns None if the write would block.
849 [clinic start generated code]*/
850 
851 static 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() */
881 static PyObject *
882 portable_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 
950 Move to new file position and return the file position.
951 
952 Argument offset is a byte count.  Optional argument whence defaults to
953 SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values
954 are SEEK_CUR or 1 (move relative to current position, positive or negative),
955 and SEEK_END or 2 (move relative to end of file, usually negative, although
956 many platforms allow seeking beyond the end of a file).
957 
958 Note that not all file objects are seekable.
959 [clinic start generated code]*/
960 
961 static 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 
974 Current file position.
975 
976 Can raise OSError for non seekable files.
977 [clinic start generated code]*/
978 
979 static 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 
995 Truncate the file to at most size bytes and return the truncated size.
996 
997 Size defaults to the current file position, as returned by tell().
998 The current file position is changed to the value of size.
999 [clinic start generated code]*/
1000 
1001 static 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 
1056 static const char *
1057 mode_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 
1081 static PyObject *
1082 fileio_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 
1119 True if the file is connected to a TTY device.
1120 [clinic start generated code]*/
1121 
1122 static 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 
1140 static 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 
1160 static PyObject *
1161 get_closed(fileio *self, void *closure)
1162 {
1163     return PyBool_FromLong((long)(self->fd < 0));
1164 }
1165 
1166 static PyObject *
1167 get_closefd(fileio *self, void *closure)
1168 {
1169     return PyBool_FromLong((long)(self->closefd));
1170 }
1171 
1172 static PyObject *
1173 get_mode(fileio *self, void *closure)
1174 {
1175     return PyUnicode_FromString(mode_string(self));
1176 }
1177 
1178 static 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 
1186 static PyMemberDef fileio_members[] = {
1187     {"_blksize", T_UINT, offsetof(fileio, blksize), 0},
1188     {"_finalizing", T_BOOL, offsetof(fileio, finalizing), 0},
1189     {NULL}
1190 };
1191 
1192 PyTypeObject 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