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