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