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